{"openapi":"3.1.0","info":{"title":"Kube-DC API","version":"v0.9.11-rabbitmq.20261021.2","description":"\nThe Kube-DC API manages everything the console does: virtual machines, Kubernetes\nworkloads and managed clusters, networking, storage, databases, secrets, and the\norganization's projects, users and billing.\n\n## Authentication\n\nEvery call except the few marked as public needs a Keycloak access token for your\norganization realm, sent as `Authorization: Bearer <token>`. The token's\norganization and group claims decide what you can see; Kubernetes RBAC on the\nproject namespace decides what you can change.\n\nTo try requests on this page, enter your organization in the bar at the top and\nchoose **Authorize** in the Authentication panel; you sign in with your usual\nKube-DC account. From scripts, get a token with the kube-dc CLI\n(`kube-dc login`). Requests made with an expired token return 401.\n\n## Quick start\n\nThe examples use the organization `acme` and its project `web`. Replace\n`<domain>` with your installation's domain.\n\n**1. Sign in and get a token.** The kube-dc CLI signs you in once and refreshes\ntokens for you:\n\n```bash\nkube-dc login --domain <domain> --org acme\nTOKEN=$(kube-dc credential --server https://kube-api.<domain>:6443 --realm acme | jq -r .status.token)\nAPI=https://backend.<domain>/api\n```\n\n**2. List the project's virtual machines.**\n\n```bash\ncurl -H \"Authorization: Bearer $TOKEN\" $API/virtual-machines/acme-web/vms\n```\n\n**3. Give a VM a public IP.** A Floating IP maps a public address to the VM;\nthe platform allocates the address:\n\n```bash\ncurl -X POST -H \"Authorization: Bearer $TOKEN\" -H \"Content-Type: application/json\" \\\n  $API/network/acme-web/fips -d '{\n    \"apiVersion\": \"kube-dc.com/v1\", \"kind\": \"FIp\",\n    \"metadata\": { \"name\": \"web-public\" },\n    \"spec\": { \"externalNetworkType\": \"public\", \"vmTarget\": { \"vmName\": \"web-1\" } }\n  }'\ncurl -H \"Authorization: Bearer $TOKEN\" $API/network/acme-web/fips/web-public\n```\n\nThe second call shows the assigned address in `status` once it is ready.\n\n## Projects and namespaces\n\nMost paths take a `{namespace}`: the project namespace, `<organization>-<project>`\n(for example `acme-web`). A few organization endpoints take the organization\nand project names separately. `GET /manage-organization/projects` lists the\norganization's projects; each project's namespace is in its `namespace` field.\n\n## Permissions\n\nWhat a token may do follows the roles you hold in Kube-DC. Organization admins\n(the `org-admin` group) manage projects, users, groups, quotas and billing.\nEveryone else works inside the projects their groups give them a role in\n(`admin`, `project-manager`, `developer`, `user` or a custom role). A call outside your\nroles returns 403 with the reason; each operation says when it needs more than\nproject access.\n\n## Requests and changes\n\n- Bodies are JSON unless the operation says otherwise. Operations that replace a\n  whole resource from its manifest (the `.../yaml` endpoints, ConfigMaps,\n  Kubernetes Secrets) take `Content-Type: application/yaml`.\n- **Replacing a resource needs its current `metadata.resourceVersion`.** Read\n  the resource, change it, and send it back; if someone changed it in between,\n  you get 409 and should read it again. Managed-service changes carry the\n  `uid` and `resourceVersion` you read for the same reason.\n- **Changes are asynchronous.** A create returns once the request is stored; the\n  platform then provisions in the background. Poll the resource until its\n  `status` says it is ready (`ready: true`, `phase: Running` or a\n  `Ready` condition, depending on the kind). Long operations answer 202 and\n  report progress on the resource they belong to.\n- **Retries.** GET and DELETE are safe to retry; a retried replace answers 409\n  when the first attempt already went through. Managed-service creates\n  take an `idempotencyKey`: generate one per user action and send the same\n  key on every retry of it, so a retried create never makes a second instance.\n\n## Errors\n\nErrors return JSON with an `error` message (some areas wrap it as\n`{ \"success\": false, \"error\": ... }`). When Kubernetes refuses a call, its\n`Status` object and status code are passed through.\n\n| Status | Meaning |\n|--------|---------|\n| 400 | The request is malformed or a field is invalid; the message names it. |\n| 401 | No token, or it expired. Get a new one. |\n| 403 | Your roles do not allow this, or a policy (allowed DNS zones, quota) refused it. |\n| 404 | The resource, or the project, does not exist. |\n| 409 | Conflict: the name is taken, or the resource changed since you read it. |\n| 422 | Understood but not possible in the current state (for example a plan limit). |\n| 503 | A service the call depends on is unavailable or not enabled on this installation; retry later. |\n\n## Lists and paging\n\nMost lists return every item at once. Lists that can grow large page explicitly\nand document their parameters: object listings take `maxKeys` and\n`continuationToken`, the audit log takes `limit` and `offset`.\n\n## Stability\n\nResponses are checked against a live installation after every backend deploy,\nand a build fails on a breaking change to a documented field, parameter or\noperation. New fields may appear in responses at any time: ignore fields you do\nnot know.\n\nAn operation is removed only after it has been deprecated for at least 90\ndays. A deprecated operation is marked on this page with its replacement and\nremoval date, listed in the Changelog, and its responses carry a\n`Deprecation` header and a `Sunset` header with the earliest removal date. The examples throughout use the organization `acme`, its project\n`web` and made-up values.\n\n## Changelog\n\nChanges to the documented API, newest first. Breaking changes are marked.\n\n### 2026-10-19\n\n- **Added:** `POST /managed-services/{namespace}/data-planes/{name}/grant/check`: Check what a grant request would do, without writing.\n- **Changed:** `GET /managed-services/{namespace}/data-planes`: each registration carries `grantWatermark`, the hub's registration watermark (null when none is recorded).\n\n### 2026-10-16\n\n- **Changed:** `GET /managed-services/{namespace}/instances/{name}`: response 200 adds `providerOwned`\n\n### 2026-10-15\n\n- **Added:** `GET /managed-services/{namespace}/data-planes`: The Project's clusters as managed-services data planes.\n- **Added:** `POST /managed-services/{namespace}/data-planes/{name}/grant`: Grant a Project cluster to run managed services.\n- **Added:** `DELETE /managed-services/{namespace}/data-planes/{name}/grant`: Withdraw a cluster grant.\n- **Changed:** `GET /managed-services/{namespace}/instances/{name}`: response 200 adds `placement`\n- **Changed:** `GET /managed-services/{namespace}/backups/{child}`: response 200 adds `sourcePlacement`\n- **Changed:** `GET /managed-services/{namespace}/instances/{name}/backups/{child}`: response 200 adds `sourcePlacement`\n\n### 2026-10-13\n\n- **Changed:** `GET /create-vm/{namespace}/storageclasses`: new query parameter `allowNodeLocal`; new query parameter `production`; new query parameter `purpose`; new query parameter `sourceClass`; new query parameter `sourcePool`; new query parameter `sourceProvisioner`\n\n### 2026-10-11\n\n- **Changed:** `GET /public/branding`: response 200 adds `disabledSections`\n\n### 2026-10-04\n\n- **Changed:** `DELETE /manage-organization/projects/{projectId}`: takes a request body\n\n### 2026-10-03\n\nFirst tracked version of the API: 392 operations. Changes from here on are listed above this entry.\n\n- **Added:** `GET /network/{namespace}/vm-addresses`: Get VM address options for a Project\n- **Changed:** `POST /create-vm/{namespace}/attach/{name}`: query parameter `is_pvc` removed\n- **Changed:** `GET /k8s-clusters/{namespace}/endpoint-options`: response 200 adds `publicAPISourcePolicyAvailable`\n"},"servers":[{"url":"/api","description":"This installation"}],"components":{"schemas":{"ProjectSpec":{"description":"ProjectSpec defines the desired state of Project.","properties":{"cidrBlock":{"description":"CidrBlock general VPC subnet IP range. When omitted, the controller\nallocates the next free block of the platform's project CIDR pool and\nrecords it here before building the project network.","type":"string"},"egressNetworkType":{"description":"EgressNetworkType controls how this project's internet gateway is addressed and accessible.\nOptions:\n- \"public\": The project's internet gateway will receive a public IP address.\n   - Resources in this project can access the internet directly and may be accessed from the internet (subject to firewall rules).\n   - Choose this if workloads require direct public internet connectivity.\n- \"cloud\": The project's internet gateway will receive an internal (private) cloud IP address only.\n   - Resources can access the internet via NAT/shared gateways, but are NOT directly accessible from the public internet.\n   - Resources can communicate with other projects in the same cloud using internal IPs.\n   - Choose this for internal workloads that should not be exposed to the public internet.","enum":["public","cloud"],"type":"string"},"gwLanIp":{"description":"GwLanIp IP address to assign to vpc nat gateway inside CidrBlock subnet","type":"string"},"network":{"description":"Network: address delegation for managed Kubernetes clusters in this\nproject (reserved LoadBalancer address blocks).","properties":{"loadBalancerBlocks":{"description":"LoadBalancerBlocks pre-allocates this many 16-address ranges from the\nproject's dedicated VPCVIPPool for managed Kubernetes LoadBalancer pools.\nEach future KdcCluster can adopt one range; without pre-allocation, a\nrange is claimed lazily when a cluster first asks for it. Grow-only: a\nreleased range tombstones by default; a proven-clean managed-cluster\nteardown returns its VPC VIP claim and ledger slot to the pool.","format":"int32","maximum":64,"minimum":0,"type":"integer"}},"type":"object"}},"required":["egressNetworkType"],"type":"object"},"ProjectStatus":{"description":"ProjectStatus defines the observed state of Project.","properties":{"conditions":{"description":"Conditions represents the latest available observations of the project's current state","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"namespace":{"description":"Namespace created for project","type":"string"},"quotaUsage":{"description":"QuotaUsage contains aggregated resource usage for this project namespace.\nPopulated by the project controller every ~60s. Human-readable values.","properties":{"accelerators":{"additionalProperties":{"description":"AcceleratorQuotaUsage holds normalized quota for one stable GPU profile ID.\nFields are optional because shared Pod and dedicated VM profiles account for\ndifferent dimensions.","properties":{"corePercent":{"description":"CorePercent is aggregate concurrent GPU compute percentage.","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"devices":{"description":"Devices is whole-device usage for passthrough, vGPU, MIG, or exclusive profiles.","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"memoryMiB":{"description":"MemoryMiB is concurrent reserved GPU framebuffer memory in MiB.","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"shares":{"description":"Shares is concurrent logical GPU allocation usage for shared Pod profiles.","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"}},"type":"object"},"description":"Accelerators maps stable GPU profile IDs to their quota dimensions.","type":"object"},"cpu":{"description":"CPU usage and limit in cores (e.g. \"1.5\" / \"8\")","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"cpuBreakdown":{"description":"CPUBreakdown splits CPU.Used between the customer's own VM/pod workloads\nand platform-managed overhead (e.g. a managed Kubernetes cluster's Kamaji\ntenant control-plane pods) that also runs inside this project's namespace\nand is counted against the same quota. Nil when the breakdown could not\nbe computed; CPU.Used remains authoritative either way.","properties":{"platformOverhead":{"description":"PlatformOverhead is CPU requested by platform-managed pods sharing this\nnamespace (e.g. managed-Kubernetes control plane, datastore), in cores.","type":"string"},"workloads":{"description":"Workloads is CPU requested by the customer's own VM/pod workloads, in cores.","type":"string"}},"type":"object"},"lastUpdated":{"description":"LastUpdated is the timestamp of the last quota status refresh","format":"date-time","type":"string"},"memory":{"description":"Memory usage and limit in GiB (e.g. \"2.5Gi\" / \"16Gi\")","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"perProjectQuotaSet":{"description":"PerProjectQuotaSet is true when an explicit per-project ResourceQuota exists","type":"boolean"},"pods":{"description":"Pods usage and hard limit (e.g. \"12\" / \"50\")","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"storage":{"description":"Storage usage and limit in GiB (e.g. \"47.3Gi\" / \"100Gi\")","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"storageAccounting":{"description":"StorageAccounting identifies the storage sample's authority. A local\nallocation sample must not fall back to native usage if its HRQ is lost.","enum":["native","local-allocation.v1"],"type":"string"}},"type":"object"},"ready":{"default":false,"description":"Ready indicates that all project objects are deployed in namespace and have no errors.","type":"boolean"},"security":{"description":"Security is the rollup of security.kube-dc.com objects (secrets,\ncertificates, KMS keys, database credentials) for this project.\nWritten by the project status aggregator in\ninternal/controller/security (see development-scope §1.6); per-CRD\nreconcilers never touch this field.","properties":{"certificateManager":{"description":"CertificateManager summarises ManagedCertificate rollup.","properties":{"count":{"description":"Count is the number of managed objects of this service in the project.","type":"integer"},"expiringSoon":{"description":"ExpiringSoon is the subset of certificates within their renewBefore\nwindow. Zero for non-certificate services.","type":"integer"},"ready":{"description":"Ready is true when the underlying service is reconcilable (OpenBao\nreachable, mounts present, policies applied) and at least one\nmanaged object exists OR the service is trivially ready with zero\nobjects.","type":"boolean"},"synced":{"description":"Synced is the subset with sync.enabled=true and Synced=True.","type":"integer"}},"type":"object"},"conditions":{"description":"Conditions: OpenBaoProjectReady, ExternalSecretsReady,\nOrganizationGroupsApplied. Per dev-scope §1.1.","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"databaseCredentials":{"description":"DatabaseCredentials summarises DatabaseCredentialPolicy rollup.","properties":{"count":{"description":"Count is the number of managed objects of this service in the project.","type":"integer"},"expiringSoon":{"description":"ExpiringSoon is the subset of certificates within their renewBefore\nwindow. Zero for non-certificate services.","type":"integer"},"ready":{"description":"Ready is true when the underlying service is reconcilable (OpenBao\nreachable, mounts present, policies applied) and at least one\nmanaged object exists OR the service is trivially ready with zero\nobjects.","type":"boolean"},"synced":{"description":"Synced is the subset with sync.enabled=true and Synced=True.","type":"integer"}},"type":"object"},"databaseMount":{"description":"DatabaseMount is the Project-owned managed-services database engine.","type":"string"},"kms":{"description":"KMS summarises KMSKey rollup.","properties":{"count":{"description":"Count is the number of managed objects of this service in the project.","type":"integer"},"expiringSoon":{"description":"ExpiringSoon is the subset of certificates within their renewBefore\nwindow. Zero for non-certificate services.","type":"integer"},"ready":{"description":"Ready is true when the underlying service is reconcilable (OpenBao\nreachable, mounts present, policies applied) and at least one\nmanaged object exists OR the service is trivially ready with zero\nobjects.","type":"boolean"},"synced":{"description":"Synced is the subset with sync.enabled=true and Synced=True.","type":"integer"}},"type":"object"},"kvMount":{"description":"KvMount is the OpenBao KV v2 mount path used by the project's\nManagedSecret resources. Empty until M1.","type":"string"},"secretStoreName":{"description":"SecretStoreName is the External Secrets Operator SecretStore in the\nproject namespace pointing at the project's KV mount. Empty until M1.","type":"string"},"secretsManager":{"description":"SecretsManager summarises ManagedSecret rollup for the project.","properties":{"count":{"description":"Count is the number of managed objects of this service in the project.","type":"integer"},"expiringSoon":{"description":"ExpiringSoon is the subset of certificates within their renewBefore\nwindow. Zero for non-certificate services.","type":"integer"},"ready":{"description":"Ready is true when the underlying service is reconcilable (OpenBao\nreachable, mounts present, policies applied) and at least one\nmanaged object exists OR the service is trivially ready with zero\nobjects.","type":"boolean"},"synced":{"description":"Synced is the subset with sync.enabled=true and Synced=True.","type":"integer"}},"type":"object"},"servicePublicationMount":{"description":"ServicePublicationMount is the separate Project-UID-bound KV v2 mount.\nRetirement preserves its value-free CAS tombstones; it is never reused.","type":"string"},"servicePublicationSecretStore":{"description":"ServicePublicationSecretStore delivers provider-owned credentials through ESO.","type":"string"},"servicePublicationServiceAccount":{"description":"ServicePublicationServiceAccount is the Project-incarnation ESO identity.","type":"string"},"syncServiceAccount":{"description":"SyncServiceAccount is the dedicated ServiceAccount used by ESO to\nauthenticate to OpenBao via auth/k8s-host. Conventionally\n`openbao-external-secrets`.","type":"string"}},"type":"object"}},"type":"object"},"Project":{"type":"object","description":"Project is the Schema for the projects API.","x-kubernetes-group-version-kind":{"group":"kube-dc.com","version":"v1","kind":"Project"},"properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"Project"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/ProjectSpec"},"status":{"$ref":"#/components/schemas/ProjectStatus"}}},"ProjectList":{"type":"object","description":"A list of Project objects.","properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"ProjectList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/Project"}}}},"OrganizationSpec":{"description":"OrganizationSpec defines the desired state of Organization.","properties":{"description":{"description":"Description is a brief description of the organization","maxLength":128,"pattern":"^[a-zA-Z0-9\\s.,\\-']+$","type":"string"},"email":{"description":"Email is a organization contact email address","maxLength":256,"minLength":5,"type":"string"},"externalCommerce":{"description":"ExternalCommerce, when present, means the organization buys its capacity\noutside Kube-DC (for example from a hosting provider that sets\nspec.quota). The console then offers no plans, add-ons or checkout, the\nbilling API refuses purchases, and users are pointed to the provider.\nSetting, changing or clearing it requires the custom \"allocate\" verb.","properties":{"portalURL":{"description":"PortalURL is the provider's customer portal, where users buy capacity.","maxLength":2048,"pattern":"^https://[^\\s@]+$","type":"string"},"providerName":{"description":"ProviderName is shown to the organization's users, e.g. \"Webdock\".","maxLength":64,"minLength":1,"type":"string"}},"required":["providerName"],"type":"object"},"quota":{"description":"Quota is the explicit capacity granted to this organization. When set it\ntakes precedence over any billing plan: the amounts become the\norganization's HierarchicalResourceQuota, public IP, load balancer, object\nstorage and GPU limits. Setting or changing it requires the custom\n\"allocate\" verb on organizations (protect-organization-policy).","properties":{"cpu":{"anyOf":[{"type":"integer"},{"type":"string"}],"description":"CPU is the total CPU requests the organization may use, excluding the\nper-project system overhead the platform adds on top.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"gpu":{"additionalProperties":{"description":"OrganizationGPUGrant is the capacity granted for one GPU catalog profile.","properties":{"corePercent":{"format":"int64","minimum":0,"type":"integer"},"devices":{"format":"int64","minimum":0,"type":"integer"},"memoryMiB":{"format":"int64","minimum":0,"type":"integer"},"shares":{"format":"int64","minimum":0,"type":"integer"}},"type":"object"},"description":"GPU maps a GPU catalog profile id to the capacity granted for it. Unknown\nor disabled profiles are rejected by the controller.","maxProperties":32,"type":"object"},"loadBalancers":{"description":"LoadBalancers caps the number of LoadBalancer Services across all projects.","format":"int64","minimum":0,"type":"integer"},"memory":{"anyOf":[{"type":"integer"},{"type":"string"}],"description":"Memory is the total memory requests the organization may use, excluding\nthe per-project system overhead the platform adds on top.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"objectStorage":{"description":"ObjectStorage is the S3 capacity. Omitted means no object storage.","properties":{"buckets":{"description":"Buckets caps the number of buckets; 0 means the platform default.","format":"int32","minimum":0,"type":"integer"},"size":{"anyOf":[{"type":"integer"},{"type":"string"}],"description":"Size is the total object storage capacity, e.g. \"1Ti\".","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]}},"required":["size"],"type":"object"},"pods":{"description":"Pods caps the number of pods across all projects.","format":"int64","minimum":0,"type":"integer"},"publicIPs":{"description":"PublicIPs caps the number of public IPv4 addresses (EIPs) across all projects.","format":"int32","minimum":0,"type":"integer"},"storage":{"anyOf":[{"type":"integer"},{"type":"string"}],"description":"Storage is the total persistent volume capacity the organization may request.","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"templatePlan":{"description":"TemplatePlan names a billing plan that supplies policy shape only (burst\nratio and LimitRange defaults). It never contributes capacity.","maxLength":63,"type":"string"}},"type":"object"},"security":{"description":"Security holds Organization-level security policy declarations.\nAdded in M2: scopes ManagedCertificate SAN issuance per Project.","properties":{"certificateDomains":{"description":"CertificateDomains scopes the DNS names tenants may put in their\nManagedCertificate spec.dnsNames per Project. The list is consulted\nby the ManagedCertificate validating webhook at admission time and\ncopied to the per-Project OpenBao PKI role (allowed_domains) at\nsigning time — defence in depth. Resolution semantics are locked\nin dev-scope §7 (resolveAllowedZones algorithm); critically, a nil\nprivateDnsNames falls back to the project's *.<project>.internal\ndefaults, while an explicit empty slice ([]) means \"no zones\nallowed for that cert type\" (Org admin opted out).\n\nlistType=map + listMapKey=project makes duplicate Project entries\na server-side reject at the apiserver — no need to teach\nLookupProject which one wins.","items":{"description":"ProjectCertificateDomainPolicy declares the DNS zones allowed for one\nProject under this Organization. Project entries are matched by name\nagainst the project namespace's kube-dc.com/project=<org>/<project>\nannotation; a Project absent from the list inherits defaults.","properties":{"privateDnsNames":{"description":"PrivateDnsNames lists DNS names that ManagedCertificate type=private\nin this Project may request. Single-label wildcard prefix allowed\n(e.g. \"*.docs.internal\"); \"**\" and mid/suffix wildcards rejected.\n\nnil    → project inherits the default\n         [ \"<project>.internal\", \"*.<project>.internal\" ].\n[]     → Org admin opted the project out; no private certs allowed.\n[...]  → explicit allowlist (replaces the default).","items":{"maxLength":253,"pattern":"^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$","type":"string"},"type":"array"},"project":{"description":"Project is the bare Project name (no org prefix). Must be a\nDNS-1123 label.","maxLength":63,"minLength":1,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$","type":"string"},"publicDnsNames":{"description":"PublicDnsNames lists DNS names that ManagedCertificate type=public\nin this Project may request. Same nil-vs-empty semantics as\nPrivateDnsNames, except the DEFAULT is empty: public certs always\nrequire an explicit Org-admin allowlist.\n\nnil    → project inherits the default ([] — no public certs).\n[]     → same as nil for public.\n[...]  → explicit allowlist.","items":{"maxLength":253,"pattern":"^(\\*\\.)?[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$","type":"string"},"type":"array"}},"required":["project"],"type":"object"},"type":"array"}},"type":"object"},"suspension":{"description":"Suspension, when present, suspends the organization independently of any\nbilling subscription state. Setting, changing or clearing it requires the\ncustom \"suspend\" verb on organizations, so a billing integration cannot\nrelease an operator's suspension and vice versa.","properties":{"reason":{"description":"Reason is shown to operators and the organization's users.","maxLength":256,"type":"string"},"stopWorkloads":{"description":"StopWorkloads scales the organization's workloads down while keeping all\ndata. When false the organization is held: its quota drops to the\nplatform's suspended floor but running workloads are not stopped.\nClearing the suspension restores workloads that were stopped.","type":"boolean"}},"type":"object"}},"required":["email"],"type":"object"},"OrganizationStatus":{"description":"OrganizationStatus defines the observed state of Organization.","properties":{"conditions":{"description":"Conditions represents the latest available observations of the organization's current state","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"quotaEnforced":{"description":"QuotaEnforced indicates whether a HierarchicalResourceQuota is active for this organization","type":"boolean"},"quotaPlanId":{"description":"QuotaPlanId is the billing plan ID currently enforced via HRQ, empty if no quota","type":"string"},"quotaUsage":{"description":"QuotaUsage holds aggregated resource usage across all dimensions (CPU, memory, storage,\npods, public IPs, object storage). Updated periodically by the organization controller.\nRead by the UI using the user's JWT token — no SA token required for quota display.","properties":{"accelerators":{"additionalProperties":{"description":"AcceleratorQuotaUsage holds normalized quota for one stable GPU profile ID.\nFields are optional because shared Pod and dedicated VM profiles account for\ndifferent dimensions.","properties":{"corePercent":{"description":"CorePercent is aggregate concurrent GPU compute percentage.","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"devices":{"description":"Devices is whole-device usage for passthrough, vGPU, MIG, or exclusive profiles.","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"memoryMiB":{"description":"MemoryMiB is concurrent reserved GPU framebuffer memory in MiB.","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"shares":{"description":"Shares is concurrent logical GPU allocation usage for shared Pod profiles.","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"}},"type":"object"},"description":"Accelerators maps stable GPU profile IDs to their quota dimensions.","type":"object"},"cpu":{"description":"CPU usage across all project namespaces (requests.cpu from HRQ)","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"lastUpdated":{"description":"LastUpdated is the timestamp when this usage was last refreshed","format":"date-time","type":"string"},"memory":{"description":"Memory usage across all project namespaces (requests.memory from HRQ)","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"objectStorage":{"description":"ObjectStorage is total S3 usage across all project buckets (in bytes)","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"pods":{"description":"Pods count across all project namespaces","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"publicIPv4":{"description":"PublicIPv4 is the count of public EIPs across all project namespaces","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"},"storage":{"description":"Storage usage across all project namespaces (requests.storage from HRQ)","properties":{"hard":{"description":"Hard is the maximum allowed amount from the active quota","type":"string"},"used":{"description":"Used is the currently consumed amount (e.g. \"2500m\", \"7Gi\", \"3\")","type":"string"}},"required":["hard","used"],"type":"object"}},"type":"object"},"ready":{"default":false,"description":"Ready indicates whether the organization is fully configured and operational","type":"boolean"},"security":{"description":"Security holds the OpenBao integration state for this Organization\n(namespace mount, OIDC auth accessor, intermediate CA expiry, etc).\nWritten by internal/organization/res_openbao_*.go reconcilers during\nOrganization Sync. See ProjectSecurityStatus for the per-Project view\nand development-scope §1.6 for the aggregator/per-CRD write model.","properties":{"authAccessor":{"description":"AuthAccessor is the stable accessor ID of the auth/k8s-host mount\ninside the Organization namespace. Stored on status so policy\ntemplates can reference it without re-reading on every reconcile\n(parent PRD §9.5).","type":"string"},"conditions":{"description":"Conditions: OpenBaoNamespaceReady, OpenBaoKubernetesAuthReady,\nOpenBaoOIDCAuthReady, OpenBaoPoliciesReady. See parent PRD §9.5.","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"lastSnapshot":{"description":"LastSnapshot is the most recent successful OpenBao Raft snapshot\ntimestamp reported by the snapshot CronJob (best-effort).","format":"date-time","type":"string"},"namespace":{"description":"Namespace is the OpenBao Namespace path created for this\nOrganization (typically equals metadata.name, e.g. \"shalb/\").","type":"string"},"oidcAccessor":{"description":"OIDCAccessor is the stable accessor ID of the auth/oidc-keycloak\nmount inside the Organization namespace (M1+ when OIDC ships).","type":"string"},"pkiExpiry":{"description":"PKIExpiry is the not-after of the Organization intermediate CA\n(M2). Empty until the PKI reconciler runs.","format":"date-time","type":"string"}},"type":"object"}},"required":["ready"],"type":"object"},"Organization":{"type":"object","description":"Organization is the Schema for the organizations API.","x-kubernetes-group-version-kind":{"group":"kube-dc.com","version":"v1","kind":"Organization"},"properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"Organization"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/OrganizationSpec"},"status":{"$ref":"#/components/schemas/OrganizationStatus"}}},"OrganizationList":{"type":"object","description":"A list of Organization objects.","properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"OrganizationList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/Organization"}}}},"OrganizationGroupSpec":{"description":"OrganizationGroupSpec defines the desired state of OrganizationGroup.","properties":{"permissions":{"description":"INSERT ADDITIONAL SPEC FIELDS - desired state of cluster","items":{"properties":{"project":{"type":"string"},"roles":{"items":{"type":"string"},"type":"array"}},"required":["project","roles"],"type":"object"},"type":"array"}},"type":"object"},"OrganizationGroupStatus":{"description":"OrganizationGroupStatus defines the observed state of OrganizationGroup.","type":"object"},"OrganizationGroup":{"type":"object","description":"OrganizationGroup is the Schema for the organizationgroups API.","x-kubernetes-group-version-kind":{"group":"kube-dc.com","version":"v1","kind":"OrganizationGroup"},"properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"OrganizationGroup"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/OrganizationGroupSpec"},"status":{"$ref":"#/components/schemas/OrganizationGroupStatus"}}},"OrganizationGroupList":{"type":"object","description":"A list of OrganizationGroup objects.","properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"OrganizationGroupList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationGroup"}}}},"EIpSpec":{"description":"EIpSpec defines the desired state of EIp.","properties":{"childRef":{"description":"ChildRef child object reference","type":"string"},"externalNetworkType":{"description":"ExternalNetworkType specifies the type of external network for this EIP.\nOptions:\n- \"public\": The EIP will be allocated from the public IP pool.\n   - The assigned IP will be accessible from the public internet (subject to firewall rules).\n   - Use this for resources that need to be reachable from outside the cloud.\n- \"cloud\": The EIP will be allocated from the internal cloud IP pool.\n   - The assigned IP will NOT be accessible from the public internet, but can be used for internal cloud communication.\n   - Use this for resources that should only be reachable within the cloud environment.","type":"string"}},"type":"object"},"EIpStatus":{"description":"EIpStatus defines the observed state of EIp.","properties":{"conditions":{"description":"Conditions represents the latest available observations of the EIp's current state","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"deleteReleased":{"description":"DeleteReleased indicates whether the EIP should be automatically deleted when released","type":"boolean"},"ipAddress":{"description":"IpAddress is the allocated external IP address","type":"string"},"ovnEIpRef":{"description":"OvnEipRef is the reference to the corresponding OVN external IP resource","type":"string"},"owners":{"description":"Owners contains the list of resources that currently own this EIP","items":{"properties":{"ownerRef":{"type":"string"},"type":{"type":"string"}},"type":"object"},"type":"array"},"ownershipType":{"default":"Released","description":"Ownerships represents the current ownership status of this EIP (Released, Exclusive, or Shared)","type":"string"},"ready":{"default":false,"description":"Ready indicates whether the EIP is properly configured and usable","type":"boolean"}},"required":["ovnEIpRef","ownershipType","ready"],"type":"object"},"EIp":{"type":"object","description":"EIp is the Schema for the eips API.","x-kubernetes-group-version-kind":{"group":"kube-dc.com","version":"v1","kind":"EIp"},"properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"EIp"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/EIpSpec"},"status":{"$ref":"#/components/schemas/EIpStatus"}}},"EIpList":{"type":"object","description":"A list of EIp objects.","properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"EIpList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/EIp"}}}},"FIpSpec":{"description":"FIpSpec defines the desired state of FIp.","properties":{"allowedCIDRs":{"description":"AllowedCIDRs restricts inbound clients to these IPv4 networks. Omitted\nor empty means unrestricted. Restrictive values require the operator\nto enable the qualified FIP source-policy capability.","items":{"maxLength":18,"pattern":"^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}/(3[0-2]|[12]?[0-9])$","type":"string"},"maxItems":32,"type":"array"},"eip":{"type":"string"},"externalNetworkType":{"description":"ExternalNetworkType specifies the type of external network for this floating IP.\nOptions:\n- \"public\": The FIP will be allocated from the public IP pool.\n   - The assigned IP will be accessible from the public internet (subject to firewall rules).\n   - Use this for workloads that require direct internet access.\n- \"cloud\": The FIP will be allocated from the internal cloud IP pool.\n   - The assigned IP will NOT be accessible from the public internet, but can be used for communication between projects within the cloud.\n   - Use this for internal workloads that do not require public exposure.","enum":["public","cloud"],"type":"string"},"ipAddress":{"description":"Target IP address for direct IP targeting","type":"string"},"vmTarget":{"description":"Target VM interface for VM-based targeting","properties":{"interfaceName":{"description":"InterfaceName is the name of the network interface on the VM (optional, defaults to first interface)","type":"string"},"vmName":{"description":"VMName is the name of the VirtualMachine or VirtualMachineInstance in the same namespace","type":"string"}},"required":["vmName"],"type":"object"}},"type":"object"},"FIpStatus":{"description":"FIpStatus defines the observed state of FIp.","properties":{"conditions":{"description":"Conditions represents the latest available observations of the FIp's current state","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"eip":{"description":"EIp is the reference to the external IP resource associated with this floating IP","type":"string"},"externalIP":{"description":"ExternalIP is the allocated external IP address for this floating IP","type":"string"},"ovnFip":{"description":"OvnFip is the reference to the OVN floating IP resource","type":"string"},"ready":{"default":false,"description":"Ready indicates whether the floating IP is properly configured and usable","type":"boolean"},"resolvedTargetIP":{"description":"ResolvedTargetIP is the actual internal IP address being targeted (resolved from VM interface if vmTarget is used)","type":"string"},"sourcePolicyRevision":{"description":"SourcePolicyRevision identifies the verified OVN ACL revision. Ready\nremains false until the matching NAT and dataplane also converge.","type":"string"},"sourcePolicySpecHash":{"description":"SourcePolicySpecHash binds the source-policy lifecycle to the selected\ntarget and external address. It is controller-owned reconciliation state.","type":"string"},"targetVMInterface":{"description":"TargetVMInterface contains information about the resolved VM interface (when vmTarget is used)","properties":{"interfaceName":{"description":"InterfaceName is the resolved interface name","type":"string"},"ipAddress":{"description":"IPAddress is the current IP address of the interface","type":"string"},"mac":{"description":"MAC is the MAC address of the interface","type":"string"},"vmName":{"description":"VMName is the resolved VM name","type":"string"}},"required":["interfaceName","ipAddress","vmName"],"type":"object"}},"required":["eip","externalIP","ovnFip","ready"],"type":"object"},"FIp":{"type":"object","description":"FIp is the Schema for the fips API.","x-kubernetes-group-version-kind":{"group":"kube-dc.com","version":"v1","kind":"FIp"},"properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"FIp"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/FIpSpec"},"status":{"$ref":"#/components/schemas/FIpStatus"}}},"FIpList":{"type":"object","description":"A list of FIp objects.","properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"FIpList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/FIp"}}}},"KdcClusterSpec":{"description":"KdcClusterSpec defines the desired state of KdcCluster","properties":{"backup":{"description":"Backup configures scheduled etcd snapshots for this cluster's control\nplane. When omitted, snapshots are enabled automatically if the Project\nhas a managed-k8s-backups S3 bucket (auto-provisioned when Rook-Ceph\nis available). Set Enabled=false to opt out explicitly.","properties":{"destinationPath":{"description":"DestinationPath overrides the default S3 URI for snapshot uploads.\nDefault: s3://<OBCBucketName>/<clusterName>/, using the Project OBC ConfigMap.","type":"string"},"enabled":{"default":true,"description":"Enabled controls whether the backup CronJob is created.","type":"boolean"},"retentionDays":{"default":7,"description":"RetentionDays is the number of days to retain snapshots. Enforced\nvia S3 object lifecycle policy on the bucket; controller-driven GC\nis the fallback for backends that do not support lifecycle rules.","format":"int32","maximum":365,"minimum":1,"type":"integer"},"s3CredentialSecret":{"description":"S3CredentialSecret overrides the Secret carrying S3 credentials.\nDefault: managed-k8s-backups (auto-managed via the Project OBC).","type":"string"},"s3Endpoint":{"description":"S3Endpoint overrides the S3 endpoint URL. Default: discovered from\nthe OBC-generated ConfigMap (BUCKET_HOST + BUCKET_PORT).","type":"string"},"schedule":{"default":"0 2 * * *","description":"Schedule is a 5-field cron expression for the snapshot CronJob.","type":"string"}},"type":"object"},"controlPlane":{"description":"Control plane configuration","properties":{"autoscaling":{"description":"Autoscaling configuration for control plane containers.\nWhen omitted, a VerticalPodAutoscaler is created in\n\"InPlaceOrRecreate\" mode so requests/limits are right-sized\nfrom observed usage. To disable autoscaling and keep static\nresources, set Mode=Off and optionally provide Resources.","properties":{"maxAllowed":{"additionalProperties":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"ResourceList is a set of (resource name, quantity) pairs.","type":"object"},"description":"MaxAllowed overrides the per-container upper bound the VPA recommender\nis allowed to recommend for this cluster's control plane. When unset,\nglobal defaults apply (kube-apiserver: 2000m / 2Gi; kube-controller-manager\nand kube-scheduler: 500m / 512Mi).\n\nUse to lift the cap on genuinely heavy tenant clusters whose\nkube-apiserver working set legitimately exceeds 2 GiB (large CRD\nsurface, bursty list-watch traffic). The default is intentionally\ntight to bound the cluster-wide request bookkeeping — uncapped VPA\nrecommendations can pin master nodes at 99% memory requested while\nreal usage is far lower, blocking other pods from scheduling.\n\nOnly the kube-apiserver entry is consulted; KCM and scheduler caps\nstay at their conservative global values. Map keys must match\ncontainer names (currently only \"kube-apiserver\" is honored).","type":"object"},"minReplicas":{"description":"MinReplicas is the minimum number of CP replicas the VPA updater will\nleave running during eviction. When unset, defaults to ControlPlane.Replicas\nso VPA never reduces the CP below its desired replica count.\nOnly honored in Recreate / InPlaceOrRecreate modes.","format":"int32","type":"integer"},"mode":{"default":"InPlaceOrRecreate","description":"Mode selects how VPA applies recommendations.\n  Off               : recommendations only (no automatic adjustments)\n  Initial           : inject at pod creation, never evict to resize\n  Recreate          : evict pods to apply new sizes (disruptive)\n  InPlaceOrRecreate : K8s 1.33+ in-place resize, fallback to eviction\n                      (default; CPU resize is restart-free)","enum":["Off","Initial","Recreate","InPlaceOrRecreate"],"type":"string"}},"type":"object"},"replicas":{"default":2,"description":"Number of control plane replicas","format":"int32","type":"integer"},"resources":{"description":"Resources optionally pins static requests/limits for the tenant\ncontrol plane containers (apiServer, controllerManager, scheduler).\nWhen set, the controller writes these values to the underlying\nTenantControlPlane on every reconcile. Use this to opt out of\nVPA-driven sizing for specific clusters that need fixed capacity\n(e.g. multi-tenant production CPs with strict SLOs).\n\nBehavior matrix:\n  Resources unset, Autoscaling.Mode != Off:\n    baseline 1:1.2 ratio set ONCE on TCP creation; VPA owns\n    subsequent updates in-place.\n  Resources unset, Autoscaling.Mode == Off:\n    baseline 1:1.2 ratio reconciled to the TCP every loop.\n  Resources set:\n    supplied values reconciled to the TCP every loop, regardless\n    of Autoscaling.Mode. VPA recommendations still surface in\n    status.controlPlane.recommendations as a sizing hint.","properties":{"apiServer":{"description":"APIServer overrides resources for the kube-apiserver container.","properties":{"limits":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"Limits describes the maximum amount of compute resources allowed.","type":"object"},"requests":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"Requests describes the minimum amount of compute resources required.","type":"object"}},"type":"object"},"controllerManager":{"description":"ControllerManager overrides resources for kube-controller-manager.","properties":{"limits":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"Limits describes the maximum amount of compute resources allowed.","type":"object"},"requests":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"Requests describes the minimum amount of compute resources required.","type":"object"}},"type":"object"},"scheduler":{"description":"Scheduler overrides resources for kube-scheduler.","properties":{"limits":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"Limits describes the maximum amount of compute resources allowed.","type":"object"},"requests":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"Requests describes the minimum amount of compute resources required.","type":"object"}},"type":"object"}},"type":"object"}},"type":"object"},"dataStore":{"description":"DataStore reference","properties":{"dedicated":{"default":false,"description":"Create a dedicated DataStore for this cluster\nWhen true, creates a dedicated etcd DataStore that will be deleted with the cluster\nWhen false (default), uses an existing shared DataStore","type":"boolean"},"eipName":{"description":"EIP name to use for the dedicated DataStore LoadBalancer service\nDefaults to \"default-gw\" if not specified","type":"string"},"name":{"description":"Name of the KdcClusterDatastore to use\nIf not specified, will auto-discover in same namespace","type":"string"},"namespace":{"description":"Namespace of the DataStore (defaults to cluster namespace)","type":"string"},"port":{"description":"Port to expose the dedicated DataStore on the shared EIP\nMust be unique per EIP to avoid conflicts\nDefaults to 2379 if not specified","format":"int32","maximum":65535,"minimum":1024,"type":"integer"}},"type":"object"},"eip":{"description":"External IP configuration for API server","properties":{"create":{"default":true,"description":"Create a new EIP or use existing","type":"boolean"},"externalNetworkType":{"default":"public","description":"External network type (public/cloud)","type":"string"},"name":{"description":"Name of existing EIP to use (if create=false)","type":"string"}},"type":"object"},"enableClusterAPI":{"default":false,"description":"Enable Cluster API integration\nWhen enabled, creates CAPI Cluster and KamajiControlPlane resources","type":"boolean"},"encryption":{"description":"Encryption configures cluster-level encryption-at-rest. When omitted,\nthe cluster runs with plaintext etcd contents (matching the historic\nbehaviour).","properties":{"etcd":{"description":"Etcd opts the cluster into etcd-at-rest encryption via a sidecar KMS\nplugin backed by an OpenBao Transit KEK. See the design doc for the\nenvelope model: the kube-apiserver owns object encryption; the plugin\nonly wraps/unwraps per-object DEKs.","properties":{"backup":{"description":"Backup configures the snapshot-file wrapper (Layer 2). When omitted,\nthe same KMSKey as KeyRef is reused — simpler restore, single key\nto protect. See design doc §9.2 for the rationale.","properties":{"keyRef":{"description":"KeyRef names a KMSKey for the backup snapshot wrapper. Defaults to\nEtcdEncryptionSpec.KeyRef. Must have purpose=etcd or purpose=backup.\nSame validation rules as EtcdEncryptionSpec.KeyRef.","type":"string"}},"type":"object"},"disableRequested":{"description":"DisableRequested drives the two-step disable migration. Setting\nDisableRequested=true while Enabled=true is the documented path to\nturn encryption off without orphaning encrypted etcd rows:\n\n  1. Tenant sets DisableRequested=true.\n  2. Controller walks `Resources` and PUTs every object so the\n     apiserver re-encrypts each row with the identity provider\n     (i.e. plaintext) under the still-active KMS provider.\n  3. Controller verifies no rows carry the `k8s:enc:kms:v2:`\n     prefix.\n  4. Controller detaches the KMS provider from\n     EncryptionConfiguration.\n  5. Tenant may now flip Enabled=false.\n\nProgress surfaces via status.encryption.disableMigrationProgress.","type":"boolean"},"enabled":{"default":false,"description":"Enabled toggles the feature on.\n\nThe disable path is NOT a simple flip — once an encrypted write has\nlanded, the controller requires the two-step DisableRequested flow\n(see field below) so encrypted rows are rewrapped to identity before\nthe KMS provider is detached. A break-glass admin annotation\n`security.kube-dc.com/encryption-force-disable-confirmed=<RFC3339>`\nbypasses the migration for incident response.","type":"boolean"},"kekRotation":{"description":"KEKRotationSpec configures automatic rotation of the per-cluster KEK\n(Transit key) that wraps every etcd DEK and every backup DEK.\n\nRotation is implemented by the M3 KMSKey reconciler in kube-dc-manager\nvia spec.rotation on the underlying KMSKey CR. This block is the\ntenant-facing knob; the kdccluster reconciler mirrors it onto the\nauto-provisioned KMSKey at FU1 ensure-time.\n\nOld key versions are kept by OpenBao until an operator explicitly\nadvances min_decryption_version (manual + irreversible; never done\nby automation). This means a KEK rotation does NOT invalidate\nexisting backups — their captured transitKeyVersion still decrypts.","properties":{"enabled":{"default":false,"description":"Enabled toggles scheduled rotation. Default: false. Even when\nencryption is on, rotation must be opted in explicitly.","type":"boolean"},"interval":{"description":"Interval between rotations. Required when Enabled. KubeDC duration\nstring (e.g. \"90d\", \"2160h\"). Units are d, h, m, s — matching the\nkube-dc KMSKey-side parser. \"w\" (weeks) is NOT accepted.\n\nBounded at reconcile-time to [7d, 730d]; values below the bound\nare refused because OpenBao Transit's own min_rotation_interval\nguardrail would refuse them anyway, and values above the bound\nare effectively \"never\" (operators who want that should set\nEnabled=false).\n\nWhen backups are enabled, the reconciler also refuses intervals\nlower than `spec.backup.retentionDays` to keep on-disk snapshots\nrestorable under the still-active key versions.\n\nNOTE on validation timing: there is no admission webhook for\nKdcCluster yet; refusal happens during the next reconcile and\nsurfaces as an EncryptionConfigError condition. Invalid specs\nare accepted by the apiserver but never produce side effects.","type":"string"}},"type":"object"},"keyRef":{"description":"KeyRef names a KMSKey CR in the same namespace whose OpenBao Transit\nkey acts as the KEK for etcd-row encryption (Layer 1).\n\nOptional: when omitted and Enabled=true, the controller auto-\nprovisions `<cluster>-etcd` with purpose=etcd and\ndeletionPolicy=retain. The auto-created KMSKey is associated to\nthe KdcCluster via labels — NOT a Kubernetes OwnerReference — so\nKubernetes garbage collection cannot delete the key while retained\netcd backups still reference it. Lifecycle is governed by a\nplatform-managed finalizer that releases the key only after\nretained backups have expired (see design doc §12.2).\n\nLabels set on the auto-provisioned KMSKey:\n  k8s.kube-dc.com/kdccluster: <cluster>\n  security.kube-dc.com/managed-by: kdccluster\n\nWhen provided, the KMSKey must be (a) Ready, (b) in the same\nnamespace, (c) spec.purpose=etcd, (d) not scheduled for deletion,\n(e) not already referenced by another KdcCluster unless the\nshared-key opt-in annotation `security.kube-dc.com/allow-shared-etcd-key`\nis set on this KdcCluster.","type":"string"},"resources":{"default":["secrets"],"description":"Resources is the K8s EncryptionConfiguration resources list.\nEnum-constrained in M5 to avoid foot-guns (high-churn resources\nlike `events` would multiply apiserver/KMS load; bootstrap-time\nresources can't be reached until KMS is ready).\n\nDefaults to [\"secrets\"] when omitted. Must contain at least one\nentry (empty lists are rejected at admission to prevent the\nconfusing \"enabled but encrypts nothing\" shape).","items":{"enum":["secrets","configmaps"],"type":"string"},"maxItems":2,"minItems":1,"type":"array"}},"required":["enabled"],"type":"object"}},"type":"object"},"kubelet":{"description":"Kubelet exposes a curated subset of kubelet configuration applied to\nALL worker nodes of this cluster (node-level resource reservations,\neviction thresholds, and the per-node pod cap). It is translated into\nRFC-6902 JSON patches on the kubelet configuration the control plane\nships to nodes (KamajiControlPlane.spec.kubelet.configurationJSONPatches).\n\nNOTE: kubelet config takes effect per node when the node reads its\n/var/lib/kubelet/config.yaml — i.e. immediately for NEW nodes, and for\nexisting nodes only after a reboot/replace (or `kubeadm upgrade node`).\nChanging these values does not live-reconfigure already-running kubelets.","properties":{"evictionHard":{"additionalProperties":{"description":"EvictionThreshold is a kubelet hard-eviction value: a quantity (\"500Mi\") or\na percentage (\"10%\"). Validated via OpenAPI Pattern/MaxLength (NOT CEL).","maxLength":32,"pattern":"^[0-9]+(\\.[0-9]+)?(%|m|k|Ki|M|Mi|G|Gi|T|Ti|P|Pi)?$","type":"string"},"description":"EvictionHard sets hard eviction thresholds: the node reclaims resources\n(and evicts Pods) with no grace period once a signal crosses the\nthreshold. Allowed keys (signals): \"memory.available\",\n\"nodefs.available\", \"nodefs.inodesFree\", \"imagefs.available\",\n\"imagefs.inodesFree\", \"pid.available\". Values are quantities (e.g.\n\"500Mi\") or percentages (e.g. \"10%\").\n\nMis-set eviction thresholds can make a node unschedulable or flap, so\nkeys are enum-validated (CEL) and values format-validated (Pattern). The\ncontroller also emits mergeDefaultEvictionSettings=true so a partial map\ndoes not zero the kubelet's omitted default signals.","maxProperties":6,"type":"object"},"kubeReserved":{"additionalProperties":{"description":"ReservedQuantity is a kubelet resource-reservation value, e.g. \"500m\", \"1Gi\".\nFormat + length are validated via OpenAPI Pattern/MaxLength (NOT CEL) so the\nper-value check stays off the CRD's CEL cost budget. The accepted set is a\ncurated subset of the Kubernetes quantity grammar.","maxLength":32,"pattern":"^[0-9]+(\\.[0-9]+)?(m|k|Ki|M|Mi|G|Gi|T|Ti|P|Pi)?$","type":"string"},"description":"KubeReserved reserves compute resources for Kubernetes node components\n(the kubelet, the container runtime). Allowed keys: \"cpu\", \"memory\",\n\"ephemeral-storage\". Values are quantities (e.g. \"500m\", \"1Gi\").","maxProperties":3,"type":"object"},"maxPods":{"description":"MaxPods is the maximum number of Pods that can run on a single node.\nThe kubelet default is 110. Raise it for high-density nodes (ensure the\npod CIDR per node and the CNI can accommodate it).","format":"int32","maximum":2500,"minimum":10,"type":"integer"},"systemReserved":{"additionalProperties":{"description":"ReservedQuantity is a kubelet resource-reservation value, e.g. \"500m\", \"1Gi\".\nFormat + length are validated via OpenAPI Pattern/MaxLength (NOT CEL) so the\nper-value check stays off the CRD's CEL cost budget. The accepted set is a\ncurated subset of the Kubernetes quantity grammar.","maxLength":32,"pattern":"^[0-9]+(\\.[0-9]+)?(m|k|Ki|M|Mi|G|Gi|T|Ti|P|Pi)?$","type":"string"},"description":"SystemReserved reserves compute resources for OS system daemons (sshd,\nudev, the kernel). Allowed keys: \"cpu\", \"memory\", \"ephemeral-storage\".\nValues are quantities.","maxProperties":3,"type":"object"}},"type":"object"},"loadBalancer":{"description":"LoadBalancer configures project-internal LoadBalancer VIPs: platform-owned\naddress blocks delegated to this cluster for private in-VPC Service VIPs.","properties":{"blocks":{"default":1,"description":"Blocks is how many 16-address ranges the cluster holds (default 1). A cluster\nthat needs more than 16 internal LoadBalancer addresses asks for a second\nblock; blocks are never resized in place.","format":"int32","maximum":8,"minimum":1,"type":"integer"}},"type":"object"},"network":{"description":"Network configuration","properties":{"controlPlaneEndpointMode":{"description":"ControlPlaneEndpointMode selects the stable worker API and Konnectivity\nendpoint. ProjectInternal uses a ClusterIP shadowed into the project VPC\nand requires local KubeVirt workers and dual-homed control-plane pods.\nOmitted or External preserves the external LoadBalancer endpoint.\nThis selection is immutable; changing a running worker's endpoint requires\na separate migration. External infrastructure workers must use External.","enum":["External","ProjectInternal"],"type":"string"},"podCIDR":{"default":"10.244.0.0/16","description":"Pod CIDR","type":"string"},"serviceCIDR":{"default":"10.96.0.0/12","description":"Service CIDR","type":"string"},"workerMTU":{"description":"WorkerMTU is the measured IPv4 link MTU for local managed worker images.\nProjectInternal requires an explicit value so bootstrap and Cilium use\nthe same installation setting instead of detecting the node-IP alias on lo.\nSupported images use systemd-networkd and an IPv4 DHCP default interface.\nImmutable once set; changing an established pool requires a migration.","format":"int32","maximum":9000,"minimum":576,"type":"integer"}},"type":"object"},"publicAPIAllowedCIDRs":{"description":"PublicAPIAllowedCIDRs limits the source IPv4 networks for this cluster's\npublic kube-apiserver endpoint. Omitted or empty means unrestricted.\nA /32 permits one client. Restrictions currently require a\nProjectInternal worker endpoint; external control-plane Services also\ncarry worker API and Konnectivity traffic and are rejected until the\nworker transport can be separated safely.","items":{"maxLength":18,"pattern":"^(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])(\\.(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9]?[0-9])){3}/(3[0-2]|[12]?[0-9])$","type":"string"},"maxItems":32,"type":"array"},"publicApiEndpoint":{"default":false,"type":"boolean"},"version":{"description":"Kubernetes version for the control plane","type":"string"},"workerHealthCheck":{"description":"WorkerHealthCheck configures automatic replacement of failed workers\nfor every worker pool of this cluster: k8-manager owns one Cluster API\nMachineHealthCheck per pool, and a worker whose Node stays Ready=False\nor Ready=Unknown past the timeout is deleted and recreated by its\nMachineDeployment. Pools override any field with\nworkers[].healthCheck.\n\nThe feature is OFF unless the platform operator turned it on for this\ninstallation (k8-manager WORKER_HEALTH_CHECK_MODE=opt-in or on); in\nopt-in mode a cluster participates only with enabled=true here or on\na pool. enabled=false opts this cluster out in every mode. A pool with\nfewer than two workers is never covered unless its own\nworkers[].healthCheck.enabled is true.","properties":{"enabled":{"description":"Enabled turns automatic worker replacement on or off. Unset inherits:\na pool inherits the cluster value, and the cluster inherits the\nplatform mode (on: enabled; opt-in or off: disabled). The platform\nmode off disables the feature regardless of this field.","type":"boolean"},"maxUnhealthy":{"description":"MaxUnhealthy stops all replacement in the pool while more than this\nmany of its workers are unhealthy or still starting: an integer count\nor a percentage of the pool (\"40%\", rounded down). Platform default 1,\nwhich also means one replacement at a time (the replacement counts as\nunhealthy until its Node is Ready) and no replacement at all when two\nor more workers fail together, as in a zone or network outage.\nAn integer must be between 0 and 2147483647; k8-manager gives a pool\nwith any other integer no check and reports InvalidMaxUnhealthy.","maxLength":4,"pattern":"^(100|[1-9]?[0-9])%$","oneOf":[{"type":"integer"},{"type":"string"}]},"nodeStartupTimeoutSeconds":{"description":"NodeStartupTimeoutSeconds is how long a new worker may take to\nregister its Node before it is replaced. Platform default 1800\n(30 minutes; CloudSigma servers and cold KubeVirt disk imports are\nslow). 0 disables the startup check; otherwise the minimum is 600.","format":"int32","maximum":86400,"minimum":0,"type":"integer"},"unhealthyTimeoutSeconds":{"description":"UnhealthyTimeoutSeconds is how long a worker's Node must stay\nReady=False or Ready=Unknown before the worker is replaced.\nPlatform default 600 (10 minutes). Minimum 300: shorter values\nreplace workers during ordinary reboots, kubelet restarts and brief\nnetwork partitions.","format":"int32","maximum":86400,"minimum":300,"type":"integer"}},"type":"object"},"workers":{"description":"Worker node pools configuration (requires enableClusterAPI=true)\nSupports multiple pools with different configurations","items":{"description":"WorkerPoolSpec defines a worker node pool configuration for CAPI + KubeVirt\nSupports multiple pools with different CPU, memory, and architecture profiles","properties":{"architecture":{"default":"amd64","description":"Architecture for this worker pool (amd64, arm64, etc.)\nUsed for node selection and image variants","type":"string"},"autoscaling":{"description":"Autoscaling configures horizontal node autoscaling for this pool\n(EKS-node-group semantics: replicas stays \"desired\" and the\nautoscaler moves it between minReplicas and maxReplicas). Absent\nblock = autoscaling off, behaviour identical to a static pool.\n\nNOTE this is the HORIZONTAL axis (node count). The similarly named\nspec.controlPlane.autoscaling is the control-plane VPA (vertical,\ncontainer resources).","properties":{"behavior":{"description":"Behavior tunes scaling speed and safety margins.","properties":{"scaleDown":{"description":"WorkerScaleDownPolicy bounds node removal. Disabled unless Enabled is\nexplicitly true — removing a customer's node is the highest-risk action\nthis feature can take.\n\nEvery field here is consumed by upstream cluster-autoscaler, which is the\nonly thing that removes nodes.","properties":{"cooldownSeconds":{"description":"CooldownSeconds is published to upstream cluster-autoscaler as\n--scale-down-delay-after-add (the MAXIMUM across the cluster's pools,\nbecause that flag is per-process rather than per-node-group).","format":"int32","minimum":0,"type":"integer"},"enabled":{"description":"Enabled must be explicitly true for any scale-down to occur.","type":"boolean"},"stabilizationWindowSeconds":{"format":"int32","minimum":0,"type":"integer"},"utilizationThreshold":{"description":"UtilizationThreshold is the node utilisation percentage below which a\nnode counts as removable, for ClusterAutoscaler mode ONLY. It is\npublished per-pool as the upstream\ncluster.x-k8s.io/autoscaling-options-scaledownutilizationthreshold\nannotation (upstream expresses it as a 0..1 ratio; this is the same\nnumber as a percent, so 50 here means 0.5 there).\n\nDistinct from ThresholdDelta, which is a Builtin-loop hysteresis band\nmeasured RELATIVE to the scale-up target. This one is absolute, matches\nwhat upstream actually consumes, and is what an operator means by \"remove\na node once it drops below X%\".\n\nUnset leaves the annotation off, so the pool follows cluster-autoscaler's\nown default (0.5). Ignored under Builtin.","format":"int32","maximum":100,"minimum":1,"type":"integer"}},"type":"object"},"scaleUp":{"description":"WorkerScaleUpPolicy bounds how aggressively nodes are added.\nCode-side defaults when unset: stabilization 120s, maxNodesPerStep 2,\ncooldown 300s.","properties":{"cooldownSeconds":{"description":"CooldownSeconds is the minimum gap between two scale-ups.","format":"int32","minimum":0,"type":"integer"},"maxNodesPerStep":{"description":"MaxNodesPerStep caps nodes added by one scaling decision.","format":"int32","minimum":1,"type":"integer"},"stabilizationWindowSeconds":{"description":"StabilizationWindowSeconds is how long the trigger condition must\nhold before the first node is added.","format":"int32","minimum":0,"type":"integer"}},"type":"object"}},"type":"object"},"enabled":{"description":"Enabled turns the scaling loop on for this pool. The block may be\nkept with enabled=false to preserve tuning while pausing scaling.","type":"boolean"},"maxReplicas":{"description":"MaxReplicas is the ceiling the autoscaler will never exceed.","format":"int32","minimum":1,"type":"integer"},"metrics":{"description":"Metrics enables the OPTIONAL utilisation trigger: scale up when any\nmetric exceeds its target (sustained). Requires the metrics-server\naddon in the tenant cluster; without it these are inert and only\nthe pending-pod trigger acts. Scale-down never acts on metrics\nalone.","items":{"description":"WorkerAutoscalingMetric is one utilisation target.","properties":{"targetAverageUtilization":{"description":"TargetAverageUtilization is the pool-average percentage above which\nthe pool scales up.","format":"int32","maximum":100,"minimum":1,"type":"integer"},"type":{"description":"Type of the metric.","enum":["cpu","memory"],"type":"string"}},"required":["targetAverageUtilization","type"],"type":"object"},"maxItems":2,"type":"array"},"minReplicas":{"description":"MinReplicas is the floor the autoscaler will never go below.\nDefaults to 1 when unset. 0 is allowed but scale-to-zero is still\nsubject to the platform guard: a pool may only reach 0 while\nanother pool has Ready workers.","format":"int32","minimum":0,"type":"integer"},"mode":{"default":"Builtin","description":"Mode selects WHICH autoscaler owns this pool's replicas (PRD §2).\nThe two modes are mutually exclusive by construction — `replicas` has\nexactly one writer at any time — and switching between them is safe\nbecause both respect the same min/max.\n\n  Builtin (default)\n    The k8-manager loop owns spec.workers[i].replicas. Scale-UP only:\n    unschedulable pods, plus the optional utilisation trigger. Works\n    on every provider with no tenant-side component.\n\n  ClusterAutoscaler\n    Upstream cluster-autoscaler (--cloud-provider=clusterapi) owns the\n    MachineDeployment's replicas. k8-manager SURRENDERS the field: it\n    stops reconciling replicas for this pool and instead publishes the\n    bounds as the standard CAPI node-group annotations. This is the\n    only mode that scales DOWN, because safe scale-down requires the\n    real kube-scheduler to prove a pod can be rescheduled — see the\n    header of kdccluster_workers_scaledown.go for why the hand-rolled\n    attempt was abandoned.\n\nTuning splits by mode, and each mode IGNORES the other's fields:\n  Builtin           metrics[] and behavior.scaleUp (the utilisation\n                    trigger and its stabilization window).\n  ClusterAutoscaler behavior.scaleDown — enabled, utilizationThreshold\n                    and stabilizationWindowSeconds are published as the\n                    per-node-group autoscaling-options annotations.\n                    metrics[] and behavior.scaleUp are IGNORED, because\n                    upstream scales UP on unschedulable pods only and has\n                    no utilisation trigger at all. They are stored but\n                    never read, so switching a pool back to Builtin\n                    restores whatever was configured. There is no status\n                    field marking them ignored — do not infer one.","enum":["Builtin","ClusterAutoscaler"],"type":"string"}},"required":["maxReplicas"],"type":"object"},"cloudsigma":{"description":"CloudSigma-specific configuration (used when infrastructureProvider=cloudsigma)","properties":{"ccmImage":{"description":"Cloud Controller Manager image. Leave empty to run the controller's\npinned default (DefaultCloudSigmaCCMImage in kdccluster_ccm.go), which a\nk8-manager release can move fleet-wide. Deliberately NOT a CRD default:\nan OpenAPI default is persisted into every object at admission, so the\ncontroller default could never apply and every CCM bump needed a\nper-object edit (the pre-2026-08-16 default was the mutable \":latest\").\nThe literal legacy value docker.io/shalb/cloudsigma-ccm:latest is\ntreated as unset by the controller.","type":"string"},"cpuMHz":{"description":"CPU in MHz (overrides calculation from cpuCores)\nIf not specified, CPU is calculated as: cpuCores * mhzPerCore (default: 2000 MHz per core)\nExample: 2000 = 2 GHz (1 core), 4000 = 4 GHz (2 cores with 2 GHz each)","format":"int32","minimum":1000,"type":"integer"},"diskSizeGB":{"description":"Disk size in GB (overrides default calculation from memory)\nIf not specified, disk size is calculated based on memory (e.g., 2x memory)","format":"int32","type":"integer"},"imageUUID":{"description":"CloudSigma image UUID (boot disk/image)\nThis is the VM template/image UUID from CloudSigma","type":"string"},"meta":{"additionalProperties":{"type":"string"},"description":"CloudSigma server metadata (key-value pairs)","type":"object"},"mhzPerCore":{"description":"MHz per core — set ONLY to pin an explicit per-core frequency\n(total MHz = cpuCores × mhzPerCore). When ABSENT, the platform\nsizes worker VMs at the zone's MAXIMUM per-core frequency\n(k8-manager writes smp=cpuCores with cpu=0; CAPCS >=0.1.33\nresolves the max from the CloudSigma capabilities API).\n\nNOTE: no kubebuilder default on purpose. The former default=2000\nwas API-server-injected into every pool, so the field could never\nbe absent and CloudSigma auto-derived FEWER, DOWNCLOCKED cores\nfrom the resulting total (5 configured cores became 4 @ 2.5 GHz;\nBOC 2026-07-08). Existing stored pools keep their persisted value.","format":"int32","minimum":1000,"type":"integer"},"nics":{"description":"Network interface configurations","items":{"description":"CloudSigmaNICSpec defines a CloudSigma network interface configuration.\n\nExactly one of VLAN or Public must be set:\n  - VLAN attaches the NIC to a CloudSigma VLAN. Combine with IPPoolRef\n    for static IPAM (cloud VLAN); omit for VLAN DHCP (customer-managed).\n  - Public attaches a CloudSigma public IP via DHCP. Use this together\n    with a cloud-VLAN NIC to give workers internal control-plane /\n    konnectivity reachability AND a per-worker public IP for egress\n    and LoadBalancer, without a separate NAT-GW VM.\n\nWhen the whole NICs slice is empty, CAPCS falls back to a single\npublic DHCP NIC (legacy behaviour).","properties":{"ipPoolRef":{"description":"IPPoolRef references an InClusterIPPool or GlobalInClusterIPPool for static IP allocation.\nRequired for cloud VLAN (first NIC) on private clusters (expose-route=false).\nOptional for customer VLANs — omit if customer provides their own DHCP.\nOnly meaningful for VLAN NICs.","properties":{"apiGroup":{"default":"ipam.cluster.x-k8s.io","description":"APIGroup is the API group of the pool resource","type":"string"},"kind":{"default":"InClusterIPPool","description":"Kind is the kind of the pool resource","enum":["InClusterIPPool","GlobalInClusterIPPool"],"type":"string"},"name":{"description":"Name is the name of the pool resource","type":"string"}},"required":["name"],"type":"object"},"loadBalancer":{"description":"LoadBalancer, when true, provisions this public NIC in CloudSigma's\n\"manual\" mode with no address of its own, reserved for the cloud\ncontroller manager to hang LoadBalancer IPs on.\n\nA worker's own public address is held only through its NIC binding, so\nthe CCM switching that NIC to manual — which it must do to run a second\nIP on it — hands the address back to CloudSigma. The guest keeps it on\nthe interface and the platform stops carrying it, leaving a node that\nreports Ready and can neither resolve DNS nor pull an image. Giving\nLoadBalancer IPs a NIC of their own means the worker's public NIC is\nnever switched.\n\nRequires Public. Mutually exclusive with VLAN.","type":"boolean"},"public":{"description":"Public, when true, attaches a CloudSigma public IP to this NIC via\nDHCP. Mutually exclusive with VLAN. Typical use: a second NIC\nalongside a cloud-VLAN NIC to give workers their own public IP for\negress / LoadBalancer without a NAT-GW VM.","type":"boolean"},"vlan":{"description":"VLAN UUID for the network interface. Mutually exclusive with Public.","type":"string"}},"type":"object"},"type":"array"},"privateApiEndpointIP":{"description":"PrivateAPIEndpointIP is a static IP from the customer VLAN subnet\nfor exposing the Kubernetes API via MetalLB LoadBalancer on the private VLAN.\nMust be outside the DHCP range and within the customer VLAN subnet.\nWhen set, a LoadBalancer Service is created for kube-api-proxy\nand a token-based private kubeconfig is generated as a Secret.\nOnly the first pool's value is used (one endpoint per cluster).\n\nA BARE IPv4 address — never a CIDR. The Pattern is load-bearing: this\nvalue is copied verbatim into the tenant apiserver's certSANs, the\nMetalLB LoadBalancer VIP, the CCM env and a CAPI annotation, and none of\nthose accept a prefix length. A CIDR here used to be accepted all the way\ndown until Kamaji's vtenantcontrolplane webhook refused the\nTenantControlPlane (\"altname is not a valid IP address\"), which creates\nNO control plane at all — the cluster then sits in Provisioning forever\nwith the real reason buried in a KamajiControlPlane condition the tenant\ncannot see (crk poc-02, marinambest, 2026-09-10: \"10.8.0.1/24\", 87\nminutes). Rejecting it at admission turns that dead end into an\nimmediate, readable error on the create call.","pattern":"^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)(\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)){3}$","type":"string"},"region":{"description":"CloudSigma region (zrh, lvs, sjc, tyo, or \"next\" for testing)","type":"string"},"tags":{"description":"CloudSigma server tags","items":{"type":"string"},"type":"array"}},"required":["imageUUID"],"type":"object"},"cpuCores":{"default":1,"description":"CPU cores per worker\nFor KubeVirt: Supports whole numbers (1, 2, 4, etc.)\nFor other providers: Check provider documentation","format":"int32","minimum":1,"type":"integer"},"diskSize":{"default":"10Gi","description":"Disk size for KubeVirt workers (e.g., \"10Gi\", \"20Gi\", \"40Gi\").\nOnly used when storageType=datavolume.\n\nNote on plan storage budget: the rootdisk registry import runs with\npullMethod=node (no CDI scratch PVC), so each worker consumes just\nthis size of namespace storage quota. Combined with dedicated etcd's\n10Gi-per-replica requirement, a Dev Pool's 60 GB storage allows\nroughly:\n  1-replica etcd + 1 worker @ 10Gi disk: 10 + 10 = 20 GB\n  3-replica etcd + 1 worker @ 10Gi disk: 30 + 10 = 40 GB\nDefault kept conservative so a fresh dedicated-datastore cluster on\nthe entry tier provisions without hitting the storage quota.","type":"string"},"healthCheck":{"description":"HealthCheck overrides spec.workerHealthCheck for this pool, field by\nfield (an unset field inherits the cluster value, then the platform\ndefault). Setting enabled=true here is the only way to cover a pool\nwith fewer than two workers: replacing the only worker of a pool is\nan outage of everything scheduled there and destroys node-local data.","properties":{"enabled":{"description":"Enabled turns automatic worker replacement on or off. Unset inherits:\na pool inherits the cluster value, and the cluster inherits the\nplatform mode (on: enabled; opt-in or off: disabled). The platform\nmode off disables the feature regardless of this field.","type":"boolean"},"maxUnhealthy":{"description":"MaxUnhealthy stops all replacement in the pool while more than this\nmany of its workers are unhealthy or still starting: an integer count\nor a percentage of the pool (\"40%\", rounded down). Platform default 1,\nwhich also means one replacement at a time (the replacement counts as\nunhealthy until its Node is Ready) and no replacement at all when two\nor more workers fail together, as in a zone or network outage.\nAn integer must be between 0 and 2147483647; k8-manager gives a pool\nwith any other integer no check and reports InvalidMaxUnhealthy.","maxLength":4,"pattern":"^(100|[1-9]?[0-9])%$","oneOf":[{"type":"integer"},{"type":"string"}]},"nodeStartupTimeoutSeconds":{"description":"NodeStartupTimeoutSeconds is how long a new worker may take to\nregister its Node before it is replaced. Platform default 1800\n(30 minutes; CloudSigma servers and cold KubeVirt disk imports are\nslow). 0 disables the startup check; otherwise the minimum is 600.","format":"int32","maximum":86400,"minimum":0,"type":"integer"},"unhealthyTimeoutSeconds":{"description":"UnhealthyTimeoutSeconds is how long a worker's Node must stay\nReady=False or Ready=Unknown before the worker is replaced.\nPlatform default 600 (10 minutes). Minimum 300: shorter values\nreplace workers during ordinary reboots, kubelet restarts and brief\nnetwork partitions.","format":"int32","maximum":86400,"minimum":300,"type":"integer"}},"type":"object"},"image":{"description":"Container disk image for KubeVirt workers only\nFor CloudSigma, use cloudsigma.imageUUID instead\nDefault for KubeVirt: docker.io/shalb/ubuntu-2604-container-disk:v1.36.1\n(deliberately a Go-side default, NOT a CRD default — a CRD default is\npersisted into every object at admission and can never be moved by a\nk8-manager release; see the cloudsigma.ccmImage history for the scar)","type":"string"},"infrastructureProvider":{"default":"kubevirt","description":"Infrastructure provider for this worker pool\nDetermines which CAPI infrastructure provider to use (kubevirt, aws, azure, etc.)","type":"string"},"labels":{"additionalProperties":{"type":"string"},"description":"Node labels to apply to workers in this pool","type":"object"},"memory":{"default":"2Gi","description":"Memory per worker (e.g., \"2Gi\", \"4Gi\", \"8Gi\")","type":"string"},"name":{"description":"Name of the worker pool (must be unique within cluster)\nUsed to generate MachineDeployment name: {cluster-name}-{pool-name}","pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$","type":"string"},"nodeDrainTimeoutSeconds":{"description":"NodeDrainTimeoutSeconds is forwarded to CAPI Machine.spec.nodeDrainTimeout\nfor every Machine in this pool. Controls how long CAPI waits for\nvoluntary eviction before force-deleting a node during rollout or\nscale-down. Default (when unset): CAPI default of 0 (no timeout).","format":"int32","minimum":0,"type":"integer"},"nodeVolumeDetachTimeoutSeconds":{"description":"NodeVolumeDetachTimeoutSeconds is forwarded to CAPI\nMachine.spec.nodeVolumeDetachTimeout: how long to wait for a deleting\nworker's volumes to detach before proceeding anyway. Unset applies the\nplatform default of 300 seconds — without a bound, replacing the only\nworker of a cluster that has attached PersistentVolumes deadlocks,\nbecause the drain evicts the CSI controller that would process the\ndetach. Explicit 0 restores CAPI's unlimited wait; the machine then\nproceeds only when every volume is cleanly detached.","format":"int32","minimum":0,"type":"integer"},"paused":{"description":"Paused freezes this pool's MachineDeployment rollout. Maps to\nCAPI MachineDeployment.spec.paused. Spec changes (version, image,\nlabels) are applied to the template but no Machines are replaced\nuntil paused=false. Use to plan an exact maintenance window.","type":"boolean"},"replicas":{"default":2,"description":"Number of worker replicas in this pool","format":"int32","minimum":0,"type":"integer"},"storageClassName":{"description":"StorageClassName is the infrastructure StorageClass of the worker root\ndisk. Only used when storageType=datavolume. Empty keeps the platform\ndefault, as does an empty string (local-path: node-local, fastest, but the worker stays on its\nhost). A replicated class lets workers survive host loss; it must be\nsuitable for a worker disk (block storage, dynamically provisioned, not\na bucket or scratch class), or the pool is not rolled out.\nChanging it rolls the pool onto new workers.","maxLength":253,"pattern":"^([a-z0-9]([-a-z0-9.]*[a-z0-9])?)?$","type":"string"},"storageType":{"default":"datavolume","description":"Storage type for KubeVirt workers\n- \"datavolume\": Persistent storage using DataVolume (default, recommended)\n- \"containerdisk\": Ephemeral storage using containerDisk (uses host ephemeral-storage)","enum":["datavolume","containerdisk"],"type":"string"},"strategy":{"description":"Strategy overrides the MachineDeployment rolling-update strategy.\nWhen nil, the controller keeps the current default\n(maxSurge=1, maxUnavailable=0) and reconciles drift back. When set,\nthe controller writes the supplied values and stops reconciling\nthe strategy block, letting users hand-tune mid-flight.","properties":{"maxSurge":{"anyOf":[{"type":"integer"},{"type":"string"}],"description":"MaxSurge is the maximum number of Machines that can be created\nabove the desired number of replicas during an update.\nDefaults to 1 when WorkerPoolStrategy is set but MaxSurge is omitted.","oneOf":[{"type":"integer"},{"type":"string"}]},"maxUnavailable":{"anyOf":[{"type":"integer"},{"type":"string"}],"description":"MaxUnavailable is the maximum number of Machines that can be\nunavailable during an update.\nDefaults to 0 when WorkerPoolStrategy is set but MaxUnavailable is omitted.","oneOf":[{"type":"integer"},{"type":"string"}]}},"type":"object"},"taints":{"description":"Node taints to apply to workers in this pool","items":{"description":"The node this Taint is attached to has the \"effect\" on\nany pod that does not tolerate the Taint.","properties":{"effect":{"description":"Required. The effect of the taint on pods\nthat do not tolerate the taint.\nValid effects are NoSchedule, PreferNoSchedule and NoExecute.","type":"string"},"key":{"description":"Required. The taint key to be applied to a node.","type":"string"},"timeAdded":{"description":"TimeAdded represents the time at which the taint was added.","format":"date-time","type":"string"},"value":{"description":"The taint value corresponding to the taint key.","type":"string"}},"required":["effect","key"],"type":"object"},"type":"array"},"version":{"description":"Version pins this pool's Kubernetes version. When unset, the pool\ntracks KdcClusterSpec.Version. Set this to the current version\nBEFORE bumping spec.version to perform a control-plane-only\nupgrade; clear (or raise) it later to roll the pool.\n\nMust satisfy the kubeadm version-skew rule: pool.version MAY be\nup to two minors behind cluster.version but MUST NOT exceed it.","pattern":"^v\\d+\\.\\d+\\.\\d+$","type":"string"}},"required":["name"],"type":"object"},"type":"array"}},"required":["version"],"type":"object"},"KdcClusterStatus":{"description":"KdcClusterStatus defines the observed state of KdcCluster","properties":{"backupBucket":{"description":"BackupBucket is the resolved S3 bucket name used for etcd snapshots.","type":"string"},"backupDestinationPath":{"description":"BackupDestinationPath is the resolved S3 URI prefix for etcd snapshots,\ne.g. s3://<bucket>/<clusterName>/","type":"string"},"conditions":{"description":"Conditions represent the latest available observations","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"controlPlane":{"description":"ControlPlane carries observed VPA state and per-container recommendations\nfor the tenant control plane Deployment.","properties":{"autoscalingMode":{"description":"AutoscalingMode reflects the active VPA updateMode.","type":"string"},"lastRecommendationUpdate":{"description":"LastRecommendationUpdate is when the NORMALISED recommendation last\nCHANGED (memory rounded to Mi, CPU to millicores) -- not the last time\nthe VPA was read. The recommendation is observed every reconcile; a\ntimestamp stamped on every read made every pass a status change and\nre-triggered the controller forever. A stable recommendation therefore\nkeeps its timestamp for as long as it stays stable, and this field\ncannot be used to detect a dead recommender: use the VPA object's own\nstatus for that.","format":"date-time","type":"string"},"recommendations":{"description":"Recommendations lists per-container resource recommendations from the\nVPA recommender. Empty until the recommender has collected enough\nmetrics-server samples (typically 10-30 minutes after first reconcile).","items":{"description":"ContainerRecommendation mirrors a single entry from\nVPA.status.recommendation.containerRecommendations.","properties":{"containerName":{"description":"ContainerName the recommendation applies to.","type":"string"},"lowerBound":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"LowerBound is the minimum recommended size.","type":"object"},"target":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"Target is the resource recommendation VPA would apply.","type":"object"},"uncappedTarget":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"UncappedTarget is the recommendation before applying min/max bounds.","type":"object"},"upperBound":{"additionalProperties":{"anyOf":[{"type":"integer"},{"type":"string"}],"pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"description":"UpperBound is the maximum recommended size.","type":"object"}},"required":["containerName"],"type":"object"},"type":"array"},"version":{"description":"Version is the currently-observed Kamaji control plane version,\nread from KamajiControlPlane.status.kubernetesVersion (falling\nback to spec.version when the KCP status field is empty, e.g.\npre-first-rollout). May lag spec.version briefly during a CP\nupgrade.","type":"string"}},"type":"object"},"controlPlaneReady":{"description":"ControlPlaneReady indicates if control plane is ready","type":"boolean"},"dataStoreName":{"description":"DataStoreName is the name of the referenced DataStore","type":"string"},"eipName":{"description":"EIPName is the name of the created or referenced EIP","type":"string"},"encryption":{"description":"Encryption mirrors the runtime state of etcd-at-rest encryption.\nSet only when spec.encryption.etcd is configured.","properties":{"currentKeyVersion":{"description":"CurrentKeyVersion is the OpenBao Transit `latest_version` for the L1\nKEK as last observed by the plugin's Status probe. Used by the\nrotation runbook to decide when a bulk rewrap has converged.","format":"int32","type":"integer"},"disableMigrationProgress":{"description":"DisableMigrationProgress reports the percent of selected resources\nthat have been re-encrypted with the identity provider during a\ntwo-step disable migration (spec.encryption.etcd.disableRequested).\n\nPointer so the controller can distinguish:\n  nil    : no migration in flight (clean / never started)\n  *0     : migration started, no rows touched yet\n  *1..99 : in progress\n  *100   : migration finished; controller clears the field on the\n           next reconcile after detaching the KMS provider.","format":"int32","maximum":100,"minimum":0,"type":"integer"},"kekRotation":{"description":"KEKRotation mirrors the rotation state of the underlying KMSKey, so\ntenants can see when their KEK last rotated without needing read\naccess to the KMSKey CR. Refreshed each reconcile by reading the\nresolved KMSKey's status. M5-T06.","properties":{"currentVersion":{"description":"CurrentVersion is the most recent Transit key version. The next\nencrypt operation (DEK wrap) uses this version; older DEKs and\nbackup envelopes remain decryptable via their captured version\nuntil MinDecryptionVersion advances past them.","format":"int32","type":"integer"},"enabled":{"description":"Enabled mirrors KMSKey.spec.rotation.enabled. When false (and the\ntenant did not opt in via spec.encryption.etcd.kekRotation.enabled),\nno rotation is scheduled; CurrentVersion stays at 1 indefinitely.","type":"boolean"},"lastRotatedTime":{"description":"LastRotatedTime mirrors KMSKey.status.lastRotatedTime — the wall-\nclock timestamp of the most recent successful rotation. Nil when\nthe KEK has never rotated (CurrentVersion == 1 from initial\nEnsureKey).","format":"date-time","type":"string"},"minDecryptionVersion":{"description":"MinDecryptionVersion is the lowest version still allowed to decrypt.\nWhen this advances past a backup envelope's recorded\ntransitKeyVersion, that backup becomes unrestorable. Operator-\ncontrolled only; the controllers never advance it.","format":"int32","type":"integer"},"nextRotationTime":{"description":"NextRotationTime mirrors KMSKey.status.nextRotationTime — when the\nscheduler will next call transit/keys/<key>/rotate. Nil when\nrotation is disabled or the policy is malformed.","format":"date-time","type":"string"}},"type":"object"},"kmsPluginReady":{"description":"KMSPluginReady is True once the sidecar has authenticated to OpenBao\nand reported KMS Status to the apiserver. Mirrored into the top-level\nEncryptionAvailable condition and gates webhook protections (e.g.\nkeyRef immutability becomes active once this transitions to true).","type":"boolean"},"lastRewrapCompleted":{"description":"LastRewrapCompleted timestamps the last operator-initiated bulk\nrewrap pass (M5-T06).","format":"date-time","type":"string"},"resolvedBackupKeyRef":{"description":"ResolvedBackupKeyRef mirrors the L2 backup-wrapper KMSKey.","type":"string"},"resolvedKeyRef":{"description":"ResolvedKeyRef mirrors whichever KMSKey backs L1, after any auto-\nprovisioning. Set even when spec.encryption.etcd.keyRef was omitted,\nso tenants can read the auto-created KMSKey name.","type":"string"},"rewrapInProgress":{"description":"RewrapInProgress is True while a bulk rewrap or a disable migration\nis running.","type":"boolean"}},"type":"object"},"endpoint":{"description":"Endpoint is the API server endpoint","type":"string"},"latestBackupKey":{"description":"LatestBackupKey is the S3 object key of the most recent successful snapshot.","type":"string"},"latestBackupTime":{"description":"LatestBackupTime is the timestamp of the last successful snapshot upload.","format":"date-time","type":"string"},"latestRestoreKey":{"description":"LatestRestoreKey is the S3 object key of the snapshot used for the last\nsuccessful restore.","type":"string"},"latestRestoreTime":{"description":"LatestRestoreTime is the timestamp of the last successful restore.","format":"date-time","type":"string"},"loadBalancer":{"description":"LoadBalancer mirrors the cluster's delegated address block(s).","properties":{"blocks":{"description":"Blocks in reservation order.","items":{"description":"LoadBalancerBlock is one delegated range as the reservation reports it.","properties":{"addressSpaceUID":{"description":"AddressSpaceUID is the immutable UID of the VPCVIPPool arena whose claim\ncommitted this delegation. The datapath validates it against the live\nledger so an arena replacement cannot inherit a stale certificate.","type":"string"},"delegatable":{"type":"boolean"},"enabled":{"description":"Enabled: this block is authorized in the certificate (per-block).","type":"boolean"},"message":{"type":"string"},"phase":{"description":"Phase of the reservation (Fenced, Ready, Compromised, Exhausted, ...).","type":"string"},"range":{"description":"Range \"start-stop\" (inclusive), empty until fenced.","type":"string"},"ready":{"description":"Ready / Delegatable as the reservation's conditions say them, mirrored\nonly when the condition's observedGeneration matches the reservation.","type":"boolean"},"reservation":{"description":"Reservation is the AddressReservation (cluster-scoped, kube-dc.com/v1).","type":"string"},"vipCIDR":{"description":"VIPCIDR is the VPCVIPPool CIDR the block was claimed in: VIPs live\noutside the project subnet and are realised as OVN load-balancer VIPs.","type":"string"}},"required":["reservation"],"type":"object"},"type":"array"},"configMap":{"description":"ConfigMap that carries the delegation to the tenant addon channel.","type":"string"},"enabled":{"description":"Enabled: at least one block is Ready+Delegatable and the mode allows the pool.","type":"boolean"},"mode":{"description":"Mode the manager runs in: off | observe | enable.","type":"string"},"revision":{"description":"Revision is the certificate's monotonic authorization revision.","format":"int64","type":"integer"}},"type":"object"},"phase":{"description":"Phase represents the current phase of the cluster","type":"string"},"publicApiEndpoint":{"description":"PublicAPIEndpoint is the publicly resolvable URL of the break-glass\nkube-apiserver endpoint. Populated once spec.publicApiEndpoint is\ntrue AND the underlying Envoy Gateway TLSRoute has been assigned a\nhostname by the svc-lb controller. Empty when the feature is off\nor not yet reconciled.\n\nMarketplace UI uses this as the \"ready\" signal — show the public\nhostname + download external kubeconfig button only when non-empty;\nshow \"Provisioning...\" while empty after the spec field was toggled\nto true.","type":"string"},"workerPools":{"description":"WorkerPools status for each worker pool","items":{"description":"WorkerPoolStatus defines the observed state of a worker pool","properties":{"autoscaling":{"description":"Autoscaling reports the scaling loop's state for this pool. Always\npopulated (Mode=Off when the pool has no autoscaling block) so\nconsumers can render state without inspecting the spec.","properties":{"currentCPUUtilization":{"description":"Pool-average utilisation percentages; only set when the utilisation\ntrigger is configured AND tenant metrics are reachable.","format":"int32","type":"integer"},"currentMemoryUtilization":{"format":"int32","type":"integer"},"lastScaleReason":{"description":"LastScaleReason is a human-readable explanation of the last scaling\ndecision, e.g. \"3 unschedulable pods fit this pool; +1 node\".","type":"string"},"lastScaleTime":{"description":"LastScaleTime is when the loop last changed this pool's replicas.","format":"date-time","type":"string"},"limitedBy":{"description":"LimitedBy is set when the loop WANTED to scale but could not:\n  Max | Quota | Placement | RollingUpdate\nEmpty when unconstrained. This is a first-class signal, not a log\nline — it is how an operator learns a cluster wanted to grow.","type":"string"},"maxReplicas":{"format":"int32","type":"integer"},"minReplicas":{"description":"Effective bounds after code-side defaulting.","format":"int32","type":"integer"},"mode":{"description":"Mode of the loop for this pool:\n  Off          — no autoscaling block, or enabled=false\n  PendingPods  — EKS-like trigger active (no metrics configured)\n  PendingPodsAndUtilization — both triggers configured","type":"string"}},"type":"object"},"blockedReplicas":{"description":"BlockedReplicas counts active worker Machines refused by provider billing.","format":"int32","type":"integer"},"deletingReplicas":{"description":"DeletingReplicas is the number of this pool's Machines currently\nbeing deleted (deletionTimestamp set: cordoned, draining, or waiting\nfor volume detach). Their kubelets often still report Ready, so\nMachineDeployment.status.readyReplicas alone overstates usable\ncapacity — a pool whose Machines were ALL deleting used to display\n\"Ready\". Phase reports Deleting whenever this is non-zero.","format":"int32","type":"integer"},"message":{"description":"Message explains the block and the action the account owner can take.","type":"string"},"name":{"description":"Name of the worker pool","type":"string"},"observedVersion":{"description":"ObservedVersion is the version currently running on the pool's\nMachines, derived from MachineDeployment.status.version (or the\nminimum Machine.spec.version when MD status is empty). May differ\nfrom Version while a rollout is in progress.","type":"string"},"paused":{"description":"Paused reflects whether the underlying MachineDeployment is paused.","type":"boolean"},"phase":{"description":"Phase of the worker pool, including BillingBlocked when the provider refuses provisioning.","type":"string"},"readyReplicas":{"description":"ReadyReplicas is the number of ready replicas","format":"int32","type":"integer"},"reason":{"description":"Reason is a stable code describing a provisioning block.","type":"string"},"replicas":{"description":"Replicas is the current number of replicas","format":"int32","type":"integer"},"updatedReplicas":{"description":"UpdatedReplicas is the number of Machines already at Version.\nRead from MachineDeployment.status.updatedReplicas.","format":"int32","type":"integer"},"version":{"description":"Version is the desired Kubernetes version for this pool\n(pool.Version if set, else cluster.Spec.Version).","type":"string"}},"required":["name","readyReplicas","replicas"],"type":"object"},"type":"array"},"workerRootDiskIdentity":{"additionalProperties":{"type":"string"},"description":"WorkerRootDiskIdentity records, per joined KubeVirt worker Machine (by\nname), \"<machineUID>:<pvcUID>\" — the UID of the PersistentVolumeClaim that\nbacked its root disk when the Machine first registered a Node, verified\nthrough the ownership chain (Machine -> CAPK-labelled VM -> VM UID ->\nkubevirt.io/created-by PVC owned by the VM's DataVolume). A joined worker\nwhose verified root-disk PVC UID later differs (same Machine UID) has lost\nits on-disk kubeadm state and — since Cluster API stops refreshing a\nMachine's bootstrap token once it has a nodeRef — can never re-join: the\ncontroller reports it as WorkerRootDiskReplaced (Phase 0 of the\nnode-health PRD: observe only). Entries are pruned when the Machine goes\naway and reset when a different Machine reuses the name.","type":"object"}},"type":"object"},"KdcCluster":{"type":"object","description":"KdcCluster is the Schema for the kdcclusters API","x-kubernetes-group-version-kind":{"group":"k8s.kube-dc.com","version":"v1alpha1","kind":"KdcCluster"},"properties":{"apiVersion":{"type":"string","const":"k8s.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"KdcCluster"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/KdcClusterSpec"},"status":{"$ref":"#/components/schemas/KdcClusterStatus"}}},"KdcClusterList":{"type":"object","description":"A list of KdcCluster objects.","properties":{"apiVersion":{"type":"string","const":"k8s.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"KdcClusterList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/KdcCluster"}}}},"KdcDatabaseSpec":{"description":"KdcDatabaseSpec defines the desired state of KdcDatabase","properties":{"backup":{"description":"Backup configuration","properties":{"destinationPath":{"description":"Full S3 destination path for backups (e.g., \"s3://my-bucket/my-path/\")\nDefault: s3://<namespace>-db-backups/databases/<db-name>/\nThe controller auto-creates the bucket via ObjectBucketClaim if using the default.","type":"string"},"enabled":{"default":true,"description":"Enable scheduled backups","type":"boolean"},"encryption":{"description":"Encryption opts the database backup into envelope encryption\nusing a kube-dc KMSKey (dev-scope §9, M3-T05). When enabled the\ncontroller generates a per-database 32-byte AES-256 data\nencryption key (DEK), wraps it via OpenBao Transit using the\nreferenced KMSKey, and stores both the wrapped form (canonical)\nand the plaintext form (for backup-Job consumption) in a\nper-database Kubernetes Secret. Engine-side wiring (mariadb\n--encrypt-key-file / CNPG post-process Job) follows as\nM3-T05 FU1; this first cut delivers the DEK lifecycle and\nstatus surface so operators can configure the intent today and\nthe engine wiring lands without further API churn.","properties":{"enabled":{"default":false,"description":"Enabled toggles envelope encryption. Defaults to false so\nexisting KdcDatabases keep their pre-M3-T05 backup shape.","type":"boolean"},"kmsKeyName":{"description":"KMSKeyName references a kube-dc KMSKey (security.kube-dc.com/\nv1alpha1) in the SAME namespace as this KdcDatabase. The\ncontroller resolves the key's Transit name from the KMSKey's\nstatus.keyId and wraps the DEK against that key.\n\nCross-namespace refs are forbidden by design — backups + keys\nlive in the same project trust boundary. The KMSKey's\nstatus.scheduledDeletion timestamp is honoured: if the key is\nin countdown, the controller refuses to provision a fresh DEK\n(audit-emit + status condition) until the deletion is cancelled.","minLength":1,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$","type":"string"},"postProcess":{"description":"PostProcess opts the database backup into the M3-T05 FU1\nengine-side encryption pipeline. When enabled the controller\nrenders a per-database CronJob that runs the operator-supplied\nwrapper image against the latest engine backup. The wrapper\nimage contract: read the DEK from a mounted Secret volume,\npull the newest backup from S3, encrypt with AES-256-GCM (or\nequivalent AEAD), upload `<original>.enc` plus a sidecar\nmanifest JSON, optionally delete the original. Both engines\n(CNPG + mariadb-operator) lack a CRD-native customer-supplied\nkey flow, so the post-process path is the universal\nintegration point.\n\nThe wrapper image itself is NOT shipped in this kube-dc\nrelease — tracked as M3-T05 FU1-PR-2. Operators can substitute\ntheir own image until then by overriding PostProcess.Image.","properties":{"enabled":{"default":false,"description":"Enabled toggles the post-process CronJob. Defaults to false so\nthe API surface stays invisible for DEK-only deployments.","type":"boolean"},"image":{"default":"shalb/db-backup-encryptor:v0.1.0-placeholder","description":"Image is the wrapper container image. Defaults to the\nkube-dc-shipping image once it lands (M3-T05 FU1-PR-2);\noperators can override with a custom image today by setting\nthis explicitly.\n\nImage contract (env passed by the controller):\n  DB_NAME          KdcDatabase name\n  ENGINE           \"postgresql\" | \"mariadb\"\n  S3_ENDPOINT      cluster-level S3 endpoint\n  S3_PATH          per-DB destination path (s3://...)\n  KMSKEY_NAME      the KMSKey CR name\n  KMSKEY_ID        \"<org>/transit/keys/<name>\"\n  WRAPPED_DEK_VERSION transit key version (from status)\n  DEK_DIR          mount point for the wrapped-DEK Secret\n  S3_CREDS_DIR     mount point for the S3 creds Secret","type":"string"},"imagePullSecrets":{"description":"ImagePullSecrets is forwarded onto the CronJob's pod spec for\nprivate wrapper images.","items":{"description":"LocalObjectReference contains enough information to let you locate the\nreferenced object inside the same namespace.","properties":{"name":{"default":"","description":"Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names","type":"string"}},"type":"object"},"type":"array"},"schedule":{"default":"30 2 * * *","description":"Schedule is the cron expression for the post-process Job.\nDefaults to \"30 2 * * *\" (30 minutes after the standard\ndaily-2am backup schedule) so the engine backup has time to\ncomplete + flush to S3 before the wrapper attempts to read it.\nOperators with a custom spec.backup.schedule should set this\nto ~30min after their own backup window.","type":"string"}},"required":["enabled"],"type":"object"},"wrappedDEKSecretName":{"description":"WrappedDEKSecretName overrides the generated K8s Secret name\n(default: \"<kdcdatabase-name>-backup-dek\"). The Secret carries\ntwo opaque entries:\n  - \"dek.bin\"   — 32-byte plaintext DEK (mariadb encrypt-key file)\n  - \"dek.wrap\"  — OpenBao Transit ciphertext (vault:v<n>:...)\nBoth are written on a single reconcile; on key rotation the\n.wrap field updates and .bin stays stable so backup Jobs\ndon't see in-flight changes mid-run.","type":"string"}},"required":["enabled","kmsKeyName"],"type":"object"},"retentionDays":{"default":7,"description":"Number of days to retain backups","format":"int32","maximum":365,"minimum":1,"type":"integer"},"s3CredentialSecret":{"description":"Name of the Kubernetes Secret containing S3 credentials\nThe secret must have keys: AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY\nDefault: auto-created from shared ObjectBucketClaim \"db-backups\"","type":"string"},"s3Endpoint":{"description":"S3 endpoint URL for backup storage. No default —\nkube-dc ships to many environments and a single-\ndomain default would silently route customer\nbackups to the wrong host. Set per-resource OR\nlet db-manager auto-derive from the cluster's\nconfigured object-storage endpoint.","type":"string"},"schedule":{"default":"0 2 * * *","description":"Cron schedule for backups (e.g., \"0 2 * * *\" = daily at 2am)","type":"string"}},"required":["enabled"],"type":"object"},"cpu":{"anyOf":[{"type":"integer"},{"type":"string"}],"default":"1","description":"CPU limit per instance (e.g., \"500m\", \"1\", \"2\", \"4\")\nBoth requests and limits are set to this value (Guaranteed QoS)","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"databaseName":{"default":"app","description":"Database name to create","type":"string"},"engine":{"default":"postgresql","description":"Engine type: postgresql (CloudNativePG) or mariadb (mariadb-operator)","enum":["postgresql","mariadb"],"type":"string"},"expose":{"description":"External exposure configuration","properties":{"type":{"default":"internal","description":"Exposure type:\n- \"internal\": ClusterIP only (default)\n- \"loadbalancer\": LoadBalancer Service with EIP (direct TCP:5432)\n- \"gateway\": TLS passthrough via Envoy Gateway","enum":["internal","loadbalancer","gateway"],"type":"string"}},"required":["type"],"type":"object"},"memory":{"anyOf":[{"type":"integer"},{"type":"string"}],"default":"2Gi","description":"Memory limit per instance (e.g., \"1Gi\", \"2Gi\", \"8Gi\")\nBoth requests and limits are set to this value (Guaranteed QoS)","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"parameters":{"additionalProperties":{"type":"string"},"description":"PostgreSQL configuration parameter overrides","type":"object"},"replicas":{"default":2,"description":"Number of PostgreSQL instances (1 = standalone, 2+ = HA with streaming replication)","format":"int32","maximum":9,"minimum":1,"type":"integer"},"restoreFrom":{"description":"Bootstrap-time recovery configuration. Only honored when the underlying\nengine cluster (CNPG Cluster / MariaDB) does not yet exist. Set this on\na freshly created KdcDatabase to provision it from an existing backup —\nthe safe \"restore into a new database\" path recommended by both engines.\n\nTo trigger a destructive in-place restore on an existing KdcDatabase,\nuse the annotation `kube-dc.com/restore-from: <backupName>` instead;\nthe controller will delete the engine CR + PVCs and re-bootstrap from\nthe chosen backup, then clear the annotation.","properties":{"backupName":{"description":"BackupName is the in-namespace `cnpg.io/Backup` (PostgreSQL) or\n`k8s.mariadb.com/PhysicalBackup` (MariaDB) CR to recover from.\nRequired.","type":"string"},"sourceDatabaseName":{"description":"SourceDatabaseName is the name of the original KdcDatabase the backup\nbelongs to. Set this when restoring into a NEW KdcDatabase whose name\ndiffers from the source (the recommended safe path). Used purely for\nauditing/UI display; the engine recovery uses BackupName.","type":"string"},"targetTime":{"description":"TargetTime requests point-in-time recovery to the given RFC 3339\ntimestamp. PostgreSQL only — replays the WAL archive up to this point\n(CNPG `recoveryTarget.targetTime`). Ignored for MariaDB in v1.","type":"string"}},"required":["backupName"],"type":"object"},"storage":{"anyOf":[{"type":"integer"},{"type":"string"}],"default":"20Gi","description":"Persistent storage size per instance\nCan only be increased, not decreased (PVC resize)","pattern":"^(\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))(([KMGTPE]i)|[numkMGTPE]|([eE](\\+|-)?(([0-9]+(\\.[0-9]*)?)|(\\.[0-9]+))))?$","oneOf":[{"type":"integer"},{"type":"string"}]},"storageClassName":{"description":"StorageClass for the database volumes. Optional: when empty, an existing\ndatabase keeps the class it already uses (status.storageClassName); a new\none gets the class that carries the platform \"database\" role\n(storage.kube-dc.com/roles) if that class can hold a database, else\nlocal-path. The class must suit a database: object-storage, scratch and\nno-provisioner classes are refused when the database is created.","type":"string"},"username":{"default":"app","description":"Application username (owner of the database)","type":"string"},"version":{"default":"16","description":"Database engine major version\nPostgreSQL: \"14\", \"15\", \"16\", \"17\"\nMariaDB: \"10.11\", \"11.4\"","type":"string"}},"required":["cpu","engine","memory","storage","version"],"type":"object"},"KdcDatabaseStatus":{"description":"KdcDatabaseStatus defines the observed state of KdcDatabase","properties":{"backupDestinationPath":{"description":"Resolved S3 destination path for backups","type":"string"},"backupEncryption":{"description":"BackupEncryption mirrors the observed state of the envelope-\nencryption pipeline (M3-T05). Empty when\nspec.backup.encryption is nil or .enabled=false. Populated\nafter the controller provisions the wrapped DEK Secret.","properties":{"kmsKeyId":{"description":"KMSKeyId is the OpenBao Transit key identifier\n\"<org>/transit/keys/<name>\" copied from the KMSKey CR's\nstatus.keyId at the time of the last wrap. Stored so a\nsubsequent KMSKey rename / re-creation is auditable without\nre-reading the KMSKey CR.","type":"string"},"kmsKeyName":{"description":"KMSKeyName is the KMSKey actually used for the wrapped DEK\n(echoes spec.backup.encryption.kmsKeyName once the key has\nbeen resolved + the DEK wrapped successfully).","type":"string"},"lastWrappedAt":{"description":"LastWrappedAt is when the DEK was last (re-)wrapped against\nthe KMSKey. Updated on spec change, key rotation, and on the\ninitial DEK provisioning.","format":"date-time","type":"string"},"postProcessCronJobName":{"description":"PostProcessCronJobName is the name of the CronJob the\ncontroller renders when spec.backup.encryption.postProcess\n.enabled=true. Empty when post-processing isn't requested.","type":"string"},"wrappedDEKSecretName":{"description":"WrappedDEKSecretName is the K8s Secret holding the DEK\n(dek.bin + dek.wrap). Mirrors spec when overridden,\notherwise reflects the default \"<db>-backup-dek\" name.","type":"string"},"wrappedDEKVersion":{"description":"WrappedDEKVersion is the OpenBao Transit key version that\nwrapped the current dek.wrap value. Parsed from the\n\"vault:v<n>:...\" ciphertext prefix at wrap time. When the\nKMSKey rotates, the controller re-wraps and bumps this.","type":"integer"}},"type":"object"},"conditions":{"description":"Conditions represent the latest available observations","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"endpoint":{"description":"Internal endpoint (ClusterIP service)","type":"string"},"externalEndpoint":{"description":"External endpoint (set when expose != internal)","type":"string"},"instances":{"description":"Total number of PostgreSQL instances","format":"int32","type":"integer"},"latestBackup":{"description":"Timestamp of the latest successful backup","format":"date-time","type":"string"},"observedGeneration":{"description":"Observed generation","format":"int64","type":"integer"},"openBaoEngineConfigured":{"description":"OpenBaoEngineConfigured reports whether db-manager has\nregistered this database with the per-Org OpenBao Database\nsecrets engine (M4-T01, dev-scope §8). When true, the\nKube-DC manager can safely reconcile DatabaseCredentialPolicy\nCRs that reference this KdcDatabase — it'll be able to write\nroles under <org>/database/roles/<dbname>-<rolename> and\n(for dynamic mode) issue leases. When false / missing,\nDatabaseCredentialPolicy reconciles stall with\nReady=False/Reason=DatabaseEngineUnconfigured.\n\nSet only when manager.openBao.enabled=true on the cluster.\nOn feature-off clusters this stays nil and downstream\nsecurity CRDs don't reconcile anyway.","type":"boolean"},"phase":{"description":"Phase represents the current lifecycle phase","enum":["Pending","Provisioning","Ready","Upgrading","Failed"],"type":"string"},"readyInstances":{"description":"Number of ready instances","format":"int32","type":"integer"},"restore":{"description":"Restore tracks the most recent restore operation (in-place via the\n`kube-dc.com/restore-from` annotation, or initial bootstrap from\n`spec.restoreFrom`). The controller writes this once the engine cluster\nreports Ready after a recovery so the UI can surface the source backup\nand target time used.","properties":{"backupName":{"description":"BackupName that was used as the recovery source (cnpg.io/Backup or\nk8s.mariadb.com/PhysicalBackup).","type":"string"},"completedAt":{"description":"CompletedAt records when the restore reached a terminal phase.","format":"date-time","type":"string"},"message":{"description":"Message is a human-readable explanation of the current/last phase.","type":"string"},"phase":{"description":"Phase is one of \"InProgress\", \"Succeeded\", \"Failed\".","enum":["InProgress","Succeeded","Failed"],"type":"string"},"sourceDatabaseName":{"description":"SourceDatabaseName is the original KdcDatabase the backup belonged to.\nEmpty for in-place restores where source == target.","type":"string"},"startedAt":{"description":"StartedAt records when the restore began.","format":"date-time","type":"string"},"targetTime":{"description":"TargetTime is the RFC 3339 timestamp the recovery aimed for (PG PITR).\nEmpty when the restore recovers to the latest available point.","type":"string"}},"required":["backupName","phase"],"type":"object"},"storageClassName":{"description":"StorageClass the database's volumes use. Recorded so that an engine\nobject deleted and recreated keeps its storage when spec.storageClassName\nis empty.","type":"string"},"storageUsed":{"description":"Current storage usage","type":"string"},"version":{"description":"Actual running PostgreSQL version (e.g., \"16.4\")","type":"string"}},"type":"object"},"KdcDatabase":{"type":"object","description":"KdcDatabase is the Schema for the kdcdatabases API","x-kubernetes-group-version-kind":{"group":"db.kube-dc.com","version":"v1alpha1","kind":"KdcDatabase"},"properties":{"apiVersion":{"type":"string","const":"db.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"KdcDatabase"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/KdcDatabaseSpec"},"status":{"$ref":"#/components/schemas/KdcDatabaseStatus"}}},"KdcDatabaseList":{"type":"object","description":"A list of KdcDatabase objects.","properties":{"apiVersion":{"type":"string","const":"db.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"KdcDatabaseList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/KdcDatabase"}}}},"KMSKeySpec":{"description":"KMSKeySpec declares a project-scoped encryption key backed by OpenBao\nTransit.","properties":{"algorithm":{"default":"aes256-gcm96","description":"Algorithm selects the cipher. Phase 1: symmetric only.","enum":["aes256-gcm96","chacha20-poly1305"],"type":"string"},"deletionPolicy":{"default":"retain","description":"DeletionPolicy: retain keeps the key indefinitely; schedule starts a\n30-day countdown that can be cancelled before expiry.","enum":["retain","schedule"],"type":"string"},"exportable":{"default":false,"description":"Exportable: Phase 1 enforces this to false via webhook. Field exists\nfor future use.","type":"boolean"},"purpose":{"default":"application","description":"Purpose tags the key for filtering and lifecycle policy.","enum":["application","backup","etcd"],"type":"string"},"rotation":{"description":"Rotation controls automatic key-version rotation.","properties":{"enabled":{"description":"Enabled toggles scheduled rotation.","type":"boolean"},"interval":{"description":"Interval between rotations. Required when Enabled.","pattern":"^[1-9][0-9]*(d|h|m|s|ms|us|ns)([1-9][0-9]*(d|h|m|s|ms|us|ns))*$","type":"string"}},"type":"object"}},"type":"object"},"KMSKeyStatus":{"description":"KMSKeyStatus reflects observed state.","properties":{"conditions":{"description":"Conditions: Ready, RotationScheduled, OpenBaoMounted.","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"currentVersion":{"description":"CurrentVersion is the most recent key version used for encryption.","type":"integer"},"keyId":{"description":"KeyId is the internal identifier (path) used for audit and API calls.","type":"string"},"lastRotatedTime":{"description":"LastRotatedTime is the most recent successful rotation.","format":"date-time","type":"string"},"minDecryptionVersion":{"description":"MinDecryptionVersion is the lowest version still allowed to decrypt\n(write-restricted to project-manager+).","type":"integer"},"nextRotationTime":{"description":"NextRotationTime is the next scheduled rotation.","format":"date-time","type":"string"},"scheduledDeletion":{"description":"ScheduledDeletion is set when deletionPolicy=schedule has been\ninvoked. Cancellable until this time.","format":"date-time","type":"string"}},"type":"object"},"KMSKey":{"type":"object","description":"KMSKey is the user-facing object for a project encryption key. Material\nis never returned to users; encrypt/decrypt go through the Kube-DC API.","x-kubernetes-group-version-kind":{"group":"security.kube-dc.com","version":"v1alpha1","kind":"KMSKey"},"properties":{"apiVersion":{"type":"string","const":"security.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"KMSKey"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/KMSKeySpec"},"status":{"$ref":"#/components/schemas/KMSKeyStatus"}}},"KMSKeyList":{"type":"object","description":"A list of KMSKey objects.","properties":{"apiVersion":{"type":"string","const":"security.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"KMSKeyList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/KMSKey"}}}},"ManagedSecretSpec":{"description":"ManagedSecretSpec declares *intent* for a project secret. Values are\nnever carried in spec; they are written through the Kube-DC API/CLI/UI.","properties":{"description":{"description":"Description is a short, free-text annotation surfaced in the UI.","maxLength":256,"type":"string"},"publicationRef":{"description":"PublicationRef delegates the complete credential lifecycle to the managed\nservice publisher. Tenant-authored references do not confer authority.","properties":{"name":{"minLength":1,"type":"string"},"namespace":{"minLength":1,"type":"string"},"uid":{"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"rotation":{"description":"Rotation enables controller-driven new-version generation on a schedule.\nCurrently meaningful for type=password; other types may rotate via\nout-of-band writes.","properties":{"enabled":{"description":"Enabled toggles scheduled rotation.","type":"boolean"},"generator":{"description":"Generator is honored when spec.type=password. For other types the\nrotation step is a no-op (user-driven write of a new version).","properties":{"charset":{"default":"alnum-symbol","description":"Charset selects the alphabet used by the generator.","enum":["alnum","alnum-symbol","hex"],"type":"string"},"length":{"default":32,"description":"Length of the generated password.","maximum":128,"minimum":8,"type":"integer"}},"type":"object"},"interval":{"description":"Interval between rotations. Required when Enabled.","pattern":"^[1-9][0-9]*(d|h|m|s|ms|us|ns)([1-9][0-9]*(d|h|m|s|ms|us|ns))*$","type":"string"}},"type":"object"},"sync":{"description":"Sync controls projection of values to a Kubernetes Secret via ESO.","properties":{"enabled":{"default":false,"description":"Enabled toggles ESO projection. When false (the default) the secret\nvalues live only in OpenBao and are accessed through the Kube-DC API.","type":"boolean"},"keys":{"description":"Keys to project. An empty list means \"all keys\" — preferred for the\ncommon case.","items":{"type":"string"},"type":"array"},"refreshInterval":{"default":"1h","description":"RefreshInterval is how often ESO refetches values from OpenBao.\nMinimum 1m, maximum 24h. Defaults to 1h.","pattern":"^[1-9][0-9]*(d|h|m|s|ms|us|ns)([1-9][0-9]*(d|h|m|s|ms|us|ns))*$","type":"string"},"targetSecretName":{"description":"TargetSecretName is the name of the Kubernetes Secret created/updated\nby ESO. Defaults to metadata.name if empty (set by the defaulting\nwebhook).","maxLength":253,"type":"string"}},"type":"object"},"type":{"default":"opaque","description":"Type drives UI affordances and certain controller defaults.","enum":["opaque","password","api-key","tls","db-static"],"type":"string"}},"type":"object"},"ManagedSecretStatus":{"description":"ManagedSecretStatus reflects the observed state.","properties":{"conditions":{"description":"Conditions: Ready, Synced, RotationScheduled, OpenBaoMounted.","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"currentVersion":{"description":"CurrentVersion is the latest OpenBao KV v2 version visible to the\nproject.","type":"integer"},"lastRotatedTime":{"description":"LastRotatedTime is the most recent controller-driven rotation.","format":"date-time","type":"string"},"lastSyncedTime":{"description":"LastSyncedTime is the most recent successful ESO projection.","format":"date-time","type":"string"},"nextRotationTime":{"description":"NextRotationTime is the next scheduled rotation, if any.","format":"date-time","type":"string"},"syncedSecretName":{"description":"SyncedSecretName is the Kubernetes Secret currently owned by ESO for\nthis ManagedSecret. Empty when sync is disabled or not yet ready.","type":"string"}},"type":"object"},"ManagedSecret":{"type":"object","description":"ManagedSecret is the user-facing object that declares a project secret\n(name, type, sync target, rotation policy). Values live in OpenBao and\nare written through the Kube-DC API/CLI/UI, never in spec.","x-kubernetes-group-version-kind":{"group":"security.kube-dc.com","version":"v1alpha1","kind":"ManagedSecret"},"properties":{"apiVersion":{"type":"string","const":"security.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"ManagedSecret"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/ManagedSecretSpec"},"status":{"$ref":"#/components/schemas/ManagedSecretStatus"}}},"ManagedSecretList":{"type":"object","description":"A list of ManagedSecret objects.","properties":{"apiVersion":{"type":"string","const":"security.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"ManagedSecretList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ManagedSecret"}}}},"ManagedCertificateSpec":{"description":"ManagedCertificateSpec declares a certificate request. The controller\ncreates and owns a cert-manager Certificate to fulfil it.","properties":{"dnsNames":{"description":"DnsNames are the SANs requested. Validated against the Organization's\nallowed certificate domains by the validating webhook.","items":{"type":"string"},"minItems":1,"type":"array"},"duration":{"default":"90d","description":"Duration is the issued certificate validity period.","pattern":"^[1-9][0-9]*(d|h|m|s|ms|us|ns)([1-9][0-9]*(d|h|m|s|ms|us|ns))*$","type":"string"},"ipAddresses":{"description":"IpAddresses are optional IP SANs.","items":{"type":"string"},"type":"array"},"purpose":{"default":"server","description":"Purpose maps to a controller-chosen set of x509 key-usages.","enum":["server","client","mtls","code-signing"],"type":"string"},"renewBefore":{"default":"15d","description":"RenewBefore is how long before expiry the controller renews.","pattern":"^[1-9][0-9]*(d|h|m|s|ms|us|ns)([1-9][0-9]*(d|h|m|s|ms|us|ns))*$","type":"string"},"targetSecretName":{"description":"TargetSecretName is the Kubernetes Secret that holds tls.crt/tls.key\nafter issuance.","maxLength":253,"type":"string"},"type":{"description":"Type selects between the Organization's private intermediate CA and\nthe public ACME path.","enum":["private","public"],"type":"string"}},"required":["dnsNames","targetSecretName","type"],"type":"object"},"ManagedCertificateStatus":{"description":"ManagedCertificateStatus reflects observed state.","properties":{"certificateSecretName":{"description":"CertificateSecretName mirrors spec.targetSecretName once issuance\nsucceeds, for UI consumption.","type":"string"},"conditions":{"description":"Conditions: Ready, DomainValidated, Issued, PKIReady (private only).\nReady mirrors the underlying cert-manager Certificate's Ready\ncondition (False/Unknown when the Certificate isn't yet\nobservable). Issued reports whether the target Secret holds a\nusable cert; PKIReady is False during initial OpenBao\nplatform-root/per-Org intermediate provisioning.","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"issuer":{"description":"Issuer is the OpenBao PKI mount or ACME issuer that signed the\ncurrent certificate.","type":"string"},"notAfter":{"format":"date-time","type":"string"},"notBefore":{"description":"NotBefore / NotAfter as observed from the issued certificate.","format":"date-time","type":"string"},"renewalTime":{"description":"RenewalTime is the next scheduled renewal.","format":"date-time","type":"string"}},"type":"object"},"ManagedCertificate":{"type":"object","description":"ManagedCertificate is the user-facing certificate object. It wraps\ncert-manager and the OpenBao PKI engine; tenants never deal with raw\nCertificate resources or PKI roles directly.","x-kubernetes-group-version-kind":{"group":"security.kube-dc.com","version":"v1alpha1","kind":"ManagedCertificate"},"properties":{"apiVersion":{"type":"string","const":"security.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"ManagedCertificate"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/ManagedCertificateSpec"},"status":{"$ref":"#/components/schemas/ManagedCertificateStatus"}}},"ManagedCertificateList":{"type":"object","description":"A list of ManagedCertificate objects.","properties":{"apiVersion":{"type":"string","const":"security.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"ManagedCertificateList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ManagedCertificate"}}}},"DatabaseCredentialPolicySpec":{"description":"DatabaseCredentialPolicySpec declares a credential policy for an\nexisting KdcDatabase in the same project namespace.","properties":{"databaseRef":{"description":"DatabaseRef points at a KdcDatabase in the *same project namespace*.\nCross-namespace references are impossible by API shape; the\nvalidating webhook verifies existence at admit time.","properties":{"name":{"default":"","description":"Name of the referent.\nThis field is effectively required, but due to backwards compatibility is\nallowed to be empty. Instances of this type with an empty value here are\nalmost certainly wrong.\nMore info: https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names","type":"string"}},"type":"object"},"maxTtl":{"description":"MaxTTL reserves the future maximum lease duration including renewals.","pattern":"^[1-9][0-9]*(d|h|m|s|ms|us|ns)([1-9][0-9]*(d|h|m|s|ms|us|ns))*$","type":"string"},"mode":{"description":"Mode selects static-rotated credentials or the reserved, not-yet-implemented\ndynamic API shape.","enum":["static-rotated","dynamic"],"type":"string"},"role":{"description":"Role reserves the future OpenBao Database engine role name for dynamic\nmode; the current controller does not provision or issue against it.","type":"string"},"rotation":{"description":"Rotation describes the static-rotated cadence.","properties":{"interval":{"default":"30d","description":"Interval between rotations.","pattern":"^[1-9][0-9]*(d|h|m|s|ms|us|ns)([1-9][0-9]*(d|h|m|s|ms|us|ns))*$","type":"string"},"strategy":{"default":"rolling","description":"Strategy is retained for API compatibility. The current controller applies\na single-password cutover for both values; clients must reload credentials\nbefore reconnecting.","enum":["rolling","immediate"],"type":"string"}},"type":"object"},"sync":{"description":"Sync controls projection of credentials into a Kubernetes Secret. It is\nalways disabled for the reserved dynamic mode, which currently issues\nneither leases nor a Secret.","properties":{"enabled":{"description":"Enabled toggles sync. The mutating webhook forces this to true\nfor static-rotated mode when the user omits both `sync` and\n`sync.enabled` (the 90% case — minimal manifest still projects a\nSecret), and forces it to false for dynamic mode. Explicit\nfalse on a static-rotated policy is respected.\n\nPointer type is required so the webhook can distinguish \"user\nomitted the field\" (nil) from \"user explicitly set false\". A\nplain bool with `omitempty` would conflate the two and a\nminimal manifest would silently skip Secret projection\n(M4-T02 review P1/P2).","type":"boolean"},"targetSecretName":{"description":"TargetSecretName defaults to metadata.name if empty.","maxLength":253,"type":"string"}},"type":"object"},"ttl":{"description":"TTL reserves the future lease duration for dynamic mode.","pattern":"^[1-9][0-9]*(d|h|m|s|ms|us|ns)([1-9][0-9]*(d|h|m|s|ms|us|ns))*$","type":"string"},"username":{"default":"app","description":"Username for static-rotated mode. Defaults to \"app\".","type":"string"}},"required":["databaseRef","mode"],"type":"object"},"DatabaseCredentialPolicyStatus":{"description":"DatabaseCredentialPolicyStatus reflects observed state.","properties":{"conditions":{"description":"Conditions: Ready, Synced, RotationScheduled.","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"endpoint":{"description":"Endpoint is the discovered DB endpoint (host:port) — convenience for\nUI/CLI consumption.","type":"string"},"lastRotatedTime":{"description":"LastRotatedTime is the most recent successful rotation\n(static-rotated mode only).","format":"date-time","type":"string"},"leaseSupported":{"description":"LeaseSupported reports engine-level capability reserved for future dynamic\ncredentials. A true value does not mean issuance is available; dynamic mode\nremains deferred until the controller and issue endpoint are implemented.","type":"boolean"},"nextRotationTime":{"description":"NextRotationTime is the next scheduled rotation\n(static-rotated mode only).","format":"date-time","type":"string"},"targetSecretName":{"description":"TargetSecretName mirrors spec.sync.targetSecretName after defaulting.","type":"string"},"username":{"description":"Username currently active (resolves any defaulting).","type":"string"}},"type":"object"},"DatabaseCredentialPolicy":{"type":"object","description":"DatabaseCredentialPolicy declares how Kube-DC rotates credentials for a\nKdcDatabase. Static-rotated mode produces a long-lived password that the\ncontroller rotates on a schedule. The dynamic value is reserved for API\ncompatibility; the current controller reports DynamicModeDeferred and issues\nno short-lived leases.","x-kubernetes-group-version-kind":{"group":"security.kube-dc.com","version":"v1alpha1","kind":"DatabaseCredentialPolicy"},"properties":{"apiVersion":{"type":"string","const":"security.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"DatabaseCredentialPolicy"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/DatabaseCredentialPolicySpec"},"status":{"$ref":"#/components/schemas/DatabaseCredentialPolicyStatus"}}},"DatabaseCredentialPolicyList":{"type":"object","description":"A list of DatabaseCredentialPolicy objects.","properties":{"apiVersion":{"type":"string","const":"security.kube-dc.com/v1alpha1"},"kind":{"type":"string","const":"DatabaseCredentialPolicyList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseCredentialPolicy"}}}},"ProjectRouteAttachmentSpec":{"description":"ProjectRouteAttachmentSpec grants this Project access to an organization allocation.","properties":{"allocationRef":{"description":"AllocationRef names a RoutedNetworkAllocation assigned to this Project's\norganization.","minLength":1,"type":"string"},"direction":{"default":"routed-egress","description":"Direction is routed-egress in v1. bidirectional is reserved for a future\nrelease with explicit ingress authorization.","enum":["routed-egress","bidirectional"],"type":"string"}},"required":["allocationRef"],"type":"object"},"ProjectRouteAttachmentStatus":{"description":"ProjectRouteAttachmentStatus reports effective, tenant-safe routing state.","properties":{"advertised":{"description":"Advertised lists Project VPC prefixes currently announced by the gateway.","items":{"type":"string"},"type":"array"},"conditions":{"description":"Conditions represents PolicyValid, Redundant, BgpEstablished,\nRoutesProgrammed, FailClosedArmed, and Ready observations.","items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"effectiveImports":{"description":"EffectiveImports lists external destinations currently installed in this\nProject VPC. It never contains a default route.","items":{"type":"string"},"type":"array"},"gateway":{"description":"Gateway reports desired and ready gateway replicas.","properties":{"haMode":{"description":"HAMode is bfd, exporter-health, or degraded-no-bfd.","type":"string"},"readyReplicas":{"description":"ReadyReplicas is the number currently ready to forward.","format":"int32","type":"integer"},"replicas":{"description":"Replicas is the desired replica count.","format":"int32","type":"integer"}},"required":["readyReplicas","replicas"],"type":"object"},"peers":{"description":"Peers reports per-replica BGP state. Tenant-facing APIs redact sensitive\nplatform topology where required.","items":{"description":"ProjectRoutePeerStatus reports one gateway-to-peer BGP session.","properties":{"address":{"description":"Address is the external peer address. Tenant views may redact this field.","type":"string"},"replica":{"description":"Replica identifies the gateway pod reporting the session.","type":"string"},"sinceSeconds":{"description":"SinceSeconds is the number of seconds the current state has held.","format":"int64","type":"integer"},"state":{"description":"State is the FRR BGP finite-state-machine state.","type":"string"}},"required":["address","replica","state"],"type":"object"},"type":"array"},"phase":{"description":"Phase is Pending, Programming, Ready, Degraded, Failed, or Terminating.","type":"string"},"routes":{"description":"Routes reports accepted, rejected, and advertised prefix counts.","properties":{"accepted":{"description":"Accepted is the number of learned routes admitted by IMPORT_ALLOWED.","format":"int32","type":"integer"},"advertised":{"description":"Advertised is the number of controller-derived Project prefixes exported.","format":"int32","type":"integer"},"rejected":{"description":"Rejected is the number of learned routes rejected by policy.","format":"int32","type":"integer"}},"required":["accepted","advertised","rejected"],"type":"object"}},"type":"object"},"ProjectRouteAttachment":{"type":"object","description":"ProjectRouteAttachment is an organization-authorized, Project-local request\nto connect the whole Project VPC to one Routed Network.","x-kubernetes-group-version-kind":{"group":"kube-dc.com","version":"v1","kind":"ProjectRouteAttachment"},"properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"ProjectRouteAttachment"},"metadata":{"$ref":"#/components/schemas/KubernetesObjectMeta"},"spec":{"$ref":"#/components/schemas/ProjectRouteAttachmentSpec"},"status":{"$ref":"#/components/schemas/ProjectRouteAttachmentStatus"}}},"ProjectRouteAttachmentList":{"type":"object","description":"A list of ProjectRouteAttachment objects.","properties":{"apiVersion":{"type":"string","const":"kube-dc.com/v1"},"kind":{"type":"string","const":"ProjectRouteAttachmentList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRouteAttachment"}}}},"KubernetesObjectMeta":{"type":"object","description":"Standard Kubernetes object metadata.","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"},"resourceVersion":{"type":"string","description":"Send it back unchanged on replace to detect concurrent edits."},"generation":{"type":"integer"},"creationTimestamp":{"type":"string","format":"date-time"},"deletionTimestamp":{"type":"string","format":"date-time"},"labels":{"type":"object","additionalProperties":{"type":"string"}},"annotations":{"type":"object","additionalProperties":{"type":"string"}},"finalizers":{"type":"array","items":{"type":"string"}}}},"GPUReasonCode":{"type":"string","enum":["GPU_NOT_ENTITLED","GPU_PROJECT_QUOTA_ZERO","GPU_QUOTA_EXHAUSTED","GPU_CAPACITY_FULL","GPU_PROFILE_UNAVAILABLE","GPU_PLATFORM_DEGRADED","GPU_RESOURCE_AMBIGUOUS","GPU_CONFIGURATION_MISMATCH"]},"GPUError":{"type":"object","additionalProperties":false,"required":["success","status","error"],"properties":{"success":{"type":"boolean","enum":[false]},"status":{"type":"integer","minimum":400,"maximum":599},"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","pattern":"^[A-Z0-9_]+$"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}}}},"StandardError":{"type":"object","additionalProperties":false,"required":["success","status","error"],"properties":{"success":{"type":"boolean","enum":[false]},"status":{"type":"integer","minimum":400,"maximum":599},"error":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}},"AdminError":{"type":"object","additionalProperties":false,"required":["status","error"],"properties":{"status":{"oneOf":[{"type":"string","enum":["error"]},{"type":"integer","minimum":400,"maximum":599}]},"error":{"type":"object","additionalProperties":false,"required":["code","message"],"properties":{"code":{"type":"string","pattern":"^[A-Z0-9_]+$"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":true}}}}},"GPUQuotaViolation":{"type":"object","additionalProperties":false,"required":["profileId","field","requested","organizationHard"],"properties":{"profileId":{"type":"string"},"field":{"type":"string","enum":["devices","shares","memoryMiB","corePercent"]},"requested":{"type":"string"},"organizationHard":{"type":"string"}}},"GPUQuotaMutationError":{"type":"object","additionalProperties":false,"required":["success","error","code"],"properties":{"success":{"type":"boolean","enum":[false]},"error":{"type":"string"},"code":{"type":"string","pattern":"^[A-Z0-9_]+$"},"details":{"type":"object","additionalProperties":false,"properties":{"violations":{"type":"array","items":{"$ref":"#/components/schemas/GPUQuotaViolation"}}}}}},"GPUGrantInput":{"type":"object","additionalProperties":false,"minProperties":1,"properties":{"devices":{"type":"integer","minimum":0},"shares":{"type":"integer","minimum":0},"memoryMiB":{"type":"integer","minimum":0},"corePercent":{"type":"integer","minimum":0}}},"GPUQuotaDimension":{"type":"object","additionalProperties":false,"required":["used","hard","available"],"properties":{"used":{"type":"string"},"hard":{"type":["string","null"]},"available":{"type":["string","null"]},"scope":{"type":"string","enum":["project","organization"]}}},"GPUQuotaGrant":{"type":"object","additionalProperties":false,"properties":{"devices":{"$ref":"#/components/schemas/GPUQuotaDimension"},"shares":{"$ref":"#/components/schemas/GPUQuotaDimension"},"memoryMiB":{"$ref":"#/components/schemas/GPUQuotaDimension"},"corePercent":{"$ref":"#/components/schemas/GPUQuotaDimension"}}},"StableGPUQuotaMap":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/GPUQuotaGrant"}},"GPURequestBounds":{"type":"object","additionalProperties":false,"properties":{"minMemoryMiB":{"type":"integer","minimum":0},"maxMemoryMiB":{"type":"integer","minimum":0},"memoryStepMiB":{"type":"integer","minimum":1},"minCorePercent":{"type":"integer","minimum":0,"maximum":100},"maxCorePercent":{"type":"integer","minimum":0,"maximum":100},"coreStepPercent":{"type":"integer","minimum":1,"maximum":100},"allowCustom":{"type":"boolean"},"presets":{"type":"array","items":{"$ref":"#/components/schemas/GPURequestPreset"}}}},"GPURequestPreset":{"type":"object","additionalProperties":false,"required":["id","displayName","memoryMiB","corePercent","default"],"properties":{"id":{"type":"string","pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"},"displayName":{"type":"string","minLength":1},"memoryMiB":{"type":"integer","minimum":1},"corePercent":{"type":"integer","minimum":1,"maximum":100},"default":{"type":"boolean"}}},"GPUAmounts":{"type":"object","additionalProperties":false,"properties":{"devices":{"type":"integer","minimum":0},"shares":{"type":"integer","minimum":0},"memoryMiB":{"type":"integer","minimum":0},"corePercent":{"type":"integer","minimum":0}}},"GPUCapabilityProfile":{"type":"object","additionalProperties":false,"required":["id","displayName","workload","allocation","liveMigratable","quotaDimension","request","capacity","requested","available","canCreate","willQueue","reasonCodes","health"],"properties":{"id":{"type":"string"},"displayName":{"type":"string"},"vendor":{"type":"string"},"workload":{"type":"string","enum":["pod","vm"]},"allocation":{"type":"string","enum":["hami","exclusive","mig","time-slicing","mps","passthrough","vgpu","sriov"]},"memoryMiB":{"type":"integer","minimum":0},"isolation":{"type":"string"},"liveMigratable":{"type":"boolean"},"quotaDimension":{"type":"string","enum":["devices","shares"]},"request":{"$ref":"#/components/schemas/GPURequestBounds"},"capacity":{"$ref":"#/components/schemas/GPUAmounts"},"requested":{"$ref":"#/components/schemas/GPUAmounts"},"available":{"type":"boolean"},"canCreate":{"type":"boolean"},"willQueue":{"type":"boolean"},"reasonCodes":{"type":"array","items":{"$ref":"#/components/schemas/GPUReasonCode"},"uniqueItems":true},"health":{"type":"string","enum":["Ready","Degraded","Unavailable"]}}},"GPUCapabilitiesResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":false,"required":["namespace","creationEnabled","vmCreationEnabled","vmGPUAvailable","profiles","quota","quotaScopes","lastUpdated"],"properties":{"namespace":{"type":"string"},"creationEnabled":{"type":"boolean"},"vmCreationEnabled":{"type":"boolean"},"vmGPUAvailable":{"type":"boolean"},"profiles":{"type":"array","items":{"$ref":"#/components/schemas/GPUCapabilityProfile"}},"quota":{"$ref":"#/components/schemas/StableGPUQuotaMap"},"quotaScopes":{"type":"object","additionalProperties":false,"required":["project","organization"],"properties":{"project":{"$ref":"#/components/schemas/StableGPUQuotaMap"},"organization":{"$ref":"#/components/schemas/StableGPUQuotaMap"}}},"lastUpdated":{"type":"string","format":"date-time"}}}}},"GPUSharedWorkloadRequest":{"type":"object","additionalProperties":false,"required":["profileId","name","image","replicas","memoryMiB","corePercent"],"properties":{"profileId":{"type":"string"},"name":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"},"image":{"type":"string","minLength":1,"maxLength":255},"replicas":{"type":"integer","minimum":1,"maximum":100},"memoryMiB":{"type":"integer","minimum":1},"corePercent":{"type":"integer","minimum":1},"allowQueue":{"type":"boolean"}}},"GPUSharedWorkloadAmounts":{"type":"object","additionalProperties":false,"required":["shares","memoryMiB","corePercent"],"properties":{"replicas":{"type":"integer","minimum":1},"shares":{"type":"integer","minimum":1},"memoryMiB":{"type":"integer","minimum":1},"corePercent":{"type":"integer","minimum":1}}},"GPUSharedWorkloadPreviewResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":false,"required":["name","request","totals","queued"],"properties":{"name":{"type":"string"},"request":{"$ref":"#/components/schemas/GPUSharedWorkloadAmounts"},"totals":{"$ref":"#/components/schemas/GPUSharedWorkloadAmounts"},"queued":{"type":"boolean"}}}}},"GPUSharedWorkloadCreateResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":false,"required":["namespace","name","request","totals","queued","created"],"properties":{"namespace":{"type":"string"},"name":{"type":"string"},"request":{"$ref":"#/components/schemas/GPUSharedWorkloadAmounts"},"totals":{"$ref":"#/components/schemas/GPUSharedWorkloadAmounts"},"queued":{"type":"boolean"},"created":{"type":"boolean"}}}}},"GPUSharedWorkloadReleaseResponse":{"type":"object","additionalProperties":false,"required":["success","data"],"properties":{"success":{"type":"boolean","enum":[true]},"data":{"type":"object","additionalProperties":false,"required":["namespace","name","released"],"properties":{"namespace":{"type":"string"},"name":{"type":"string"},"released":{"type":"boolean","enum":[true]}}}}},"ScalarQuotaDimension":{"type":"object","additionalProperties":false,"required":["used","hard","available"],"properties":{"used":{"type":"string"},"hard":{"type":["string","null"]},"available":{"type":["string","null"]},"enforcedHard":{"type":"string","description":"What Kubernetes enforces, when it differs from the plan's hard: the organization quota carries room for one plan-max VM's virtualization overhead. Capacity checks use it; displays keep hard. Organization CPU and memory rows only."},"enforcedAvailable":{"type":"string","description":"Headroom Kubernetes would still admit for one more VM on both quota axes; enforcedHard minus used."}}},"QuotaScope":{"type":"object","additionalProperties":true,"properties":{"cpu":{"$ref":"#/components/schemas/ScalarQuotaDimension"},"memory":{"$ref":"#/components/schemas/ScalarQuotaDimension"},"storage":{"$ref":"#/components/schemas/ScalarQuotaDimension"},"pods":{"$ref":"#/components/schemas/ScalarQuotaDimension"},"publicIPv4":{"$ref":"#/components/schemas/ScalarQuotaDimension"},"objectStorage":{"anyOf":[{"$ref":"#/components/schemas/ScalarQuotaDimension"},{"type":"null"}]},"accelerators":{"$ref":"#/components/schemas/StableGPUQuotaMap"},"perProjectQuotaSet":{"type":"boolean"},"lastUpdated":{"type":["string","null"],"format":"date-time"}}},"GPUQuotaSummaryResponse":{"type":"object","additionalProperties":false,"required":["success","data","timestamp"],"properties":{"success":{"type":"boolean","enum":[true]},"message":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":false,"required":["namespace","organization","project","org"],"properties":{"namespace":{"type":"string"},"organization":{"type":"string"},"limitRange":{"type":["object","null"],"additionalProperties":true},"project":{"anyOf":[{"$ref":"#/components/schemas/QuotaScope"},{"type":"null"}]},"org":{"anyOf":[{"$ref":"#/components/schemas/QuotaScope"},{"type":"null"}]}}}}},"GPUQuotaPreviewRequest":{"type":"object","additionalProperties":false,"required":["accelerators"],"properties":{"accelerators":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/GPUGrantInput"}}}},"GPUQuotaPreviewResponse":{"type":"object","additionalProperties":false,"required":["success","data","timestamp"],"properties":{"success":{"type":"boolean","enum":[true]},"timestamp":{"type":"string","format":"date-time"},"data":{"type":"object","additionalProperties":false,"required":["accelerators","pooled","action"],"properties":{"accelerators":{"type":"object","additionalProperties":{"$ref":"#/components/schemas/GPUGrantInput"}},"pooled":{"type":"boolean"},"action":{"type":"string","enum":["create","update","delete","none"]}}}}},"GPUInventoryProfile":{"type":"object","additionalProperties":false,"required":["id","displayName","vendor","workload","allocation","resourceName","billingEligible","isolation","health","capacity","requested","reasonCodes"],"properties":{"id":{"type":"string"},"displayName":{"type":"string"},"vendor":{"type":["string","null"]},"workload":{"type":"string","enum":["pod","vm"]},"allocation":{"type":"string"},"resourceName":{"type":"string"},"billingEligible":{"type":"boolean"},"isolation":{"type":["string","null"]},"health":{"type":"string","enum":["Ready","Degraded","Unavailable"]},"capacity":{"$ref":"#/components/schemas/GPUAmounts"},"requested":{"$ref":"#/components/schemas/GPUAmounts"},"reasonCodes":{"type":"array","items":{"$ref":"#/components/schemas/GPUReasonCode"}}}},"GPUInventoryDevice":{"type":"object","additionalProperties":false,"required":["id","index","model","health","mode","shares","memoryMiB","corePercent"],"properties":{"id":{"type":"string"},"index":{"type":"integer","minimum":0},"model":{"type":"string"},"health":{"type":"boolean"},"mode":{"type":"string"},"shares":{"type":"integer","minimum":0},"memoryMiB":{"type":"integer","minimum":0},"corePercent":{"type":"integer","minimum":0}}},"GPUInventoryNode":{"type":"object","additionalProperties":false,"required":["name","ready","mode","handshake","profiles","devices"],"properties":{"name":{"type":"string"},"ready":{"type":"boolean"},"mode":{"type":["string","null"]},"handshake":{"type":["string","null"]},"profiles":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["profileId","allocatable"],"properties":{"profileId":{"type":"string"},"allocatable":{"type":"integer","minimum":0}}}},"devices":{"type":"array","items":{"$ref":"#/components/schemas/GPUInventoryDevice"}}}},"GPUInventoryAllocation":{"type":"object","additionalProperties":false,"required":["kind","namespace","name","profileId","phase","nodeName","ownerKind","ownerName","request"],"properties":{"kind":{"type":"string","enum":["Pod","VirtualMachineInstance"]},"namespace":{"type":"string"},"name":{"type":"string"},"profileId":{"type":"string"},"phase":{"type":"string"},"nodeName":{"type":["string","null"]},"ownerKind":{"type":["string","null"]},"ownerName":{"type":["string","null"]},"request":{"$ref":"#/components/schemas/GPUAmounts"}}},"GPUInventoryResponse":{"type":"object","additionalProperties":false,"required":["status","data"],"properties":{"status":{"type":"string","enum":["success"]},"data":{"type":"object","additionalProperties":false,"required":["generatedAt","profiles","nodes","allocations","totals"],"properties":{"generatedAt":{"type":"string","format":"date-time"},"profiles":{"type":"array","items":{"$ref":"#/components/schemas/GPUInventoryProfile"}},"nodes":{"type":"array","items":{"$ref":"#/components/schemas/GPUInventoryNode"}},"allocations":{"type":"array","items":{"$ref":"#/components/schemas/GPUInventoryAllocation"}},"totals":{"type":"object","additionalProperties":false,"required":["nodes","readyNodes","devices","healthyDevices","activeAllocations"],"properties":{"nodes":{"type":"integer","minimum":0},"readyNodes":{"type":"integer","minimum":0},"devices":{"type":"integer","minimum":0},"healthyDevices":{"type":"integer","minimum":0},"activeAllocations":{"type":"integer","minimum":0}}}}}}},"ObjectBucketRotation":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"uid":{"type":"string"},"generation":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"deleting":{"type":"boolean"},"spec":{"type":"object","additionalProperties":false,"properties":{"projectRef":{"type":"object","additionalProperties":false,"properties":{"namespace":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1,"maxLength":253},"uid":{"type":"string","minLength":1,"maxLength":64}},"required":["namespace","name","uid"]},"projectNamespaceUID":{"type":"string"},"claimRef":{"type":"object","additionalProperties":false,"properties":{"namespace":{"type":"string","minLength":1,"maxLength":64},"name":{"type":"string","minLength":1,"maxLength":253},"uid":{"type":"string","minLength":1,"maxLength":64}},"required":["namespace","name","uid"]},"sourceSecretUID":{"type":"string"},"gracePeriodSeconds":{"type":"integer","minimum":60,"maximum":86400,"default":300},"abandon":{"type":"object","additionalProperties":false,"properties":{"reason":{"type":"string","minLength":1,"maxLength":256}},"required":["reason"]}},"required":["projectRef","projectNamespaceUID","claimRef","sourceSecretUID","gracePeriodSeconds"]},"status":{"type":"object","additionalProperties":false,"properties":{"phase":{"type":"string","enum":["Pending","Preparing","Publishing","AwaitingConsumers","Revoking","Succeeded","Cancelled","Abandoned"]},"objectBucketUID":{"type":"string"},"rgwUser":{"type":"string"},"sourceResourceVersion":{"type":"string"},"publishedAt":{"type":"string","format":"date-time"},"completedAt":{"type":"string","format":"date-time"},"previousFingerprint":{"type":"string"},"currentFingerprint":{"type":"string"},"retiringKeys":{"type":"array","maxItems":8,"description":"Keys abandoned predecessors left valid, which this rotation revokes after its own old key is rejected. Fingerprints only.","items":{"type":"object","additionalProperties":false,"properties":{"rotationUID":{"type":"string"},"rotationName":{"type":"string"},"previousFingerprint":{"type":"string"},"currentFingerprint":{"type":"string"},"abandonedAt":{"type":"string","format":"date-time"}},"required":["rotationUID","previousFingerprint","currentFingerprint"]}},"untrackedKeys":{"type":"integer","description":"Keys the claim user still held at success besides the current key and the keys this rotation retired (keys no rotation tracks, and retained keys whose recorded access key ID disagrees with the keyring). Reported, never revoked."},"abandon":{"type":"object","additionalProperties":false,"properties":{"outcome":{"type":"string","enum":["Deferred","Pending","Abandoned","Cancelled","Superseded"]},"observedAt":{"type":"string","format":"date-time"},"abandonedAt":{"type":"string","format":"date-time"},"result":{"type":"string","enum":["OldKeyRetained","OldKeyRevoked","RotationNotPublished","NewKeyUnverified","AuthorityUnverified"]},"verified":{"type":"boolean"},"oldKeyState":{"type":"string","enum":["Present","Absent","Unknown"]},"blockedReason":{"type":"string","maxLength":1024},"blockedMessage":{"type":"string","maxLength":1024},"stalledReason":{"type":"string","maxLength":128,"description":"The cause whose consecutive failures, each backed by evidence (a rejection or definitive refusal, a changed claim Secret, a lost intent, a claim or Secret gone, consumer reads or the registry write refused while revoking), an abandon is waiting out (ten minutes from stalledSince) before it ends a stalled rotation. A transient error (5xx, 408, 429, a conflict, a failed read) neither starts nor resets it."},"stalledSince":{"type":"string","format":"date-time"},"retirement":{"type":"string","enum":["Recorded","Skipped"]}}},"conditions":{"type":"array","items":{"type":"object","additionalProperties":false,"properties":{"type":{"type":"string"},"status":{"type":"string","enum":["True","False","Unknown"]},"observedGeneration":{"type":"integer"},"lastTransitionTime":{"type":"string","format":"date-time"},"reason":{"type":"string"},"message":{"type":"string"}},"required":["type","status","lastTransitionTime","reason","message"]}}}}},"required":["name","uid","deleting","spec","status"]},"TopologyObjectReference":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"TopologyMemberIdentity":{"properties":{"dataPlaneRef":{"properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","uid"],"type":"object"},"nativeRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"placementRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"serviceRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"}},"required":["dataPlaneRef","nativeRef","placementRef","serviceRef"],"type":"object"},"KafkaMirrorScope":{"description":"Explicit lists make missing per-topic/group observations distinguishable from\na measured zero. Wildcard scope cannot silently widen during a cutover.","properties":{"consumerGroups":{"items":{"maxLength":255,"minLength":1,"type":"string"},"maxItems":256,"type":"array"},"reverseAfterCutover":{"type":"boolean"},"topics":{"items":{"maxLength":249,"minLength":1,"pattern":"^[a-zA-Z0-9._-]+$","type":"string"},"maxItems":256,"minItems":1,"type":"array"}},"required":["topics"],"type":"object"},"ReplicationGroupSpec":{"description":"ReplicationGroupSpec owns desired topology; member status is never an input.","properties":{"family":{"enum":["postgresql","kafka"],"type":"string"},"mirror":{"$ref":"#/components/schemas/KafkaMirrorScope"},"mode":{"enum":["PostgresStreaming","KafkaMirror"],"type":"string"},"primary":{"description":"Primary is the desired member name, resolved inside this Project.","maxLength":63,"minLength":1,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$","type":"string"}},"required":["family","mode","primary"],"type":"object"},"ReplicationGroupStatus":{"properties":{"activeChange":{"properties":{"epoch":{"format":"int64","type":"integer"},"expiresAt":{"format":"date-time","type":"string"},"homeHub":{"type":"string"},"intent":{"description":"Intent freezes the desired generation and member identities in the same\nCAS as allocation, before a TopologyChange can exist. A later spec edit\ncannot retarget a reserved change after a lost create response.","properties":{"epoch":{"format":"int64","minimum":0,"type":"integer"},"groupRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"homeHub":{"maxLength":128,"minLength":1,"type":"string"},"mirror":{"description":"Explicit lists make missing per-topic/group observations distinguishable from\na measured zero. Wildcard scope cannot silently widen during a cutover.","properties":{"consumerGroups":{"items":{"maxLength":255,"minLength":1,"type":"string"},"maxItems":256,"type":"array"},"reverseAfterCutover":{"type":"boolean"},"topics":{"items":{"maxLength":249,"minLength":1,"pattern":"^[a-zA-Z0-9._-]+$","type":"string"},"maxItems":256,"minItems":1,"type":"array"}},"required":["topics"],"type":"object"},"mode":{"enum":["PostgresStreaming","KafkaMirror"],"type":"string"},"requestedGeneration":{"format":"int64","minimum":1,"type":"integer"},"sequence":{"format":"int64","minimum":1,"type":"integer"},"source":{"properties":{"dataPlaneRef":{"properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","uid"],"type":"object"},"nativeRef":{"description":"TopologyNativeReference allows admission before the runner creates the native\nroot. Only a Joining member may omit UID; every change pins an existing root.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace"],"type":"object"},"placementRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"serviceRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"}},"required":["dataPlaneRef","nativeRef","placementRef","serviceRef"],"type":"object"},"strategy":{"enum":["Planned","Emergency","Revert","Rebuild"],"type":"string"},"target":{"properties":{"dataPlaneRef":{"properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","uid"],"type":"object"},"nativeRef":{"description":"TopologyNativeReference allows admission before the runner creates the native\nroot. Only a Joining member may omit UID; every change pins an existing root.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace"],"type":"object"},"placementRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"serviceRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"}},"required":["dataPlaneRef","nativeRef","placementRef","serviceRef"],"type":"object"}},"required":["epoch","groupRef","homeHub","mode","requestedGeneration","sequence","source","strategy","target"],"type":"object"},"name":{"type":"string"},"sequence":{"format":"int64","type":"integer"},"uid":{"description":"UID is checkpointed after deterministic child creation and before dispatch.","type":"string"}},"required":["epoch","expiresAt","homeHub","name","sequence"],"type":"object"},"aliases":{"items":{"properties":{"dataPlaneRef":{"properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","uid"],"type":"object"},"epoch":{"format":"int64","type":"integer"},"primaryUID":{"type":"string"},"ready":{"type":"boolean"},"reason":{"type":"string"},"serviceRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"}},"required":["dataPlaneRef","epoch","serviceRef"],"type":"object"},"maxItems":32,"type":"array"},"bootstrapPrimaryRef":{"description":"BootstrapPrimaryRef is the initial data origin, independent of subsequent\ncommitted-primary changes. A member never changes its bootstrap method.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"conditions":{"items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"credentials":{"description":"Credentials references the private hub authority, never its values. The\nauthority UID must be checkpointed before issuing member material.","properties":{"authorityRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"caExpiresAt":{"format":"date-time","type":"string"},"profile":{"properties":{"database":{"maxLength":63,"minLength":1,"type":"string"},"owner":{"maxLength":63,"minLength":1,"type":"string"},"readonly":{"type":"boolean"}},"required":["database","owner","readonly"],"type":"object"},"revision":{"description":"Revision is a random, value-free identity for the password authority.","maxLength":32,"pattern":"^[a-f0-9]{32}$","type":"string"}},"required":["authorityRef","caExpiresAt","profile","revision"],"type":"object"},"epoch":{"format":"int64","type":"integer"},"fences":{"items":{"properties":{"actor":{"type":"string"},"changeRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"confirmedAt":{"format":"date-time","type":"string"},"epoch":{"format":"int64","type":"integer"},"evidenceDigest":{"type":"string"},"member":{"properties":{"dataPlaneRef":{"properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","uid"],"type":"object"},"nativeRef":{"description":"TopologyNativeReference allows admission before the runner creates the native\nroot. Only a Joining member may omit UID; every change pins an existing root.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace"],"type":"object"},"placementRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"serviceRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"}},"required":["dataPlaneRef","nativeRef","placementRef","serviceRef"],"type":"object"},"method":{"enum":["RunnerAcknowledged","EmergencyIsolation"],"type":"string"},"rebuiltNativeRef":{"description":"Rejoin must attest a new replica incarnation before this record can retire.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"}},"required":["changeRef","confirmedAt","epoch","evidenceDigest","member","method"],"type":"object"},"maxItems":64,"type":"array"},"homeHub":{"description":"HomeHub is the owning hub's signing key ID, pinned at admission.","type":"string"},"members":{"items":{"properties":{"archiveRevision":{"type":"string"},"conditions":{"items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"maxItems":16,"type":"array"},"credentialRevision":{"type":"string"},"credentials":{"description":"Credentials journals member material before any remote projection. Its\nnamespace UID and projection UIDs must survive renewal.","properties":{"authorityRevision":{"maxLength":32,"pattern":"^[a-f0-9]{32}$","type":"string"},"expiresAt":{"format":"date-time","type":"string"},"materialRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"namespaceUID":{"maxLength":64,"minLength":1,"type":"string"},"projections":{"items":{"properties":{"kind":{"enum":["CA","Server","Replication","Owner","Readonly"],"maxLength":11,"type":"string"},"name":{"maxLength":253,"minLength":1,"type":"string"},"sequence":{"description":"Sequence acknowledges the exact material bundle delivered to this UID.","format":"int64","minimum":1,"type":"integer"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["kind","name","sequence","uid"],"type":"object"},"maxItems":5,"type":"array"},"sequence":{"description":"Sequence increases before a new certificate bundle can be delivered.","format":"int64","minimum":1,"type":"integer"}},"required":["authorityRevision","expiresAt","materialRef","namespaceUID","sequence"],"type":"object"},"dataPlaneRef":{"properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","uid"],"type":"object"},"delaySeconds":{"format":"int32","type":"integer"},"groupUID":{"type":"string"},"lastObservedAt":{"format":"date-time","type":"string"},"nativeRef":{"description":"TopologyNativeReference allows admission before the runner creates the native\nroot. Only a Joining member may omit UID; every change pins an existing root.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace"],"type":"object"},"observedEpoch":{"format":"int64","type":"integer"},"placementRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"promotable":{"type":"boolean"},"role":{"enum":["Primary","Replica","Demoted","Fenced","Joining","Retiring"],"type":"string"},"serviceRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"uid":{"description":"UID is the stable list-map key and equals serviceRef.uid.","maxLength":64,"minLength":1,"type":"string"}},"required":["dataPlaneRef","groupUID","nativeRef","placementRef","role","serviceRef","uid"],"type":"object"},"maxItems":32,"type":"array"},"observedGeneration":{"format":"int64","type":"integer"},"primaryRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"sequence":{"description":"Sequence also advances for failed/abandoned attempts without an epoch change.","format":"int64","type":"integer"}},"type":"object"},"TopologyChangeSpec":{"description":"TopologyChangeSpec is provider-owned durable intent, never a tenant-created\nchild operation. Runtime authority also checks the group's reservation UID.","properties":{"epoch":{"format":"int64","minimum":0,"type":"integer"},"groupRef":{"$ref":"#/components/schemas/TopologyObjectReference"},"homeHub":{"maxLength":128,"minLength":1,"type":"string"},"mirror":{"$ref":"#/components/schemas/KafkaMirrorScope"},"mode":{"enum":["PostgresStreaming","KafkaMirror"],"type":"string"},"requestedGeneration":{"format":"int64","minimum":1,"type":"integer"},"sequence":{"format":"int64","minimum":1,"type":"integer"},"source":{"$ref":"#/components/schemas/TopologyMemberIdentity"},"strategy":{"enum":["Planned","Emergency","Revert","Rebuild"],"type":"string"},"target":{"$ref":"#/components/schemas/TopologyMemberIdentity"}},"required":["epoch","groupRef","homeHub","mode","requestedGeneration","sequence","source","strategy","target"],"type":"object"},"TopologyChangeStatus":{"properties":{"approval":{"description":"Approval is a provider-verified receipt, tied to immutable change identity.\nTenant input alone cannot populate this status or attest isolation.","properties":{"actor":{"type":"string"},"approvedAt":{"format":"date-time","type":"string"},"consumersMigrated":{"type":"boolean"},"evidenceDigest":{"type":"string"},"isolationConfirmed":{"type":"boolean"},"producersQuiesced":{"type":"boolean"},"unknownLossAcknowledged":{"type":"boolean"}},"required":["actor","approvedAt","evidenceDigest"],"type":"object"},"committedAt":{"format":"date-time","type":"string"},"committedEpoch":{"format":"int64","type":"integer"},"completedAt":{"format":"date-time","type":"string"},"conditions":{"items":{"description":"Condition contains details for one aspect of the current state of this API Resource.","properties":{"lastTransitionTime":{"description":"lastTransitionTime is the last time the condition transitioned from one status to another.\nThis should be when the underlying condition changed.  If that is not known, then using the time when the API field changed is acceptable.","format":"date-time","type":"string"},"message":{"description":"message is a human readable message indicating details about the transition.\nThis may be an empty string.","maxLength":32768,"type":"string"},"observedGeneration":{"description":"observedGeneration represents the .metadata.generation that the condition was set based upon.\nFor instance, if .metadata.generation is currently 12, but the .status.conditions[x].observedGeneration is 9, the condition is out of date\nwith respect to the current state of the instance.","format":"int64","minimum":0,"type":"integer"},"reason":{"description":"reason contains a programmatic identifier indicating the reason for the condition's last transition.\nProducers of specific condition types may define expected values and meanings for this field,\nand whether the values are considered a guaranteed API.\nThe value should be a CamelCase string.\nThis field may not be empty.","maxLength":1024,"minLength":1,"pattern":"^[A-Za-z]([A-Za-z0-9_,:]*[A-Za-z0-9_])?$","type":"string"},"status":{"description":"status of the condition, one of True, False, Unknown.","enum":["True","False","Unknown"],"type":"string"},"type":{"description":"type of condition in CamelCase or in foo.example.com/CamelCase.","maxLength":316,"pattern":"^([a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*/)?(([A-Za-z0-9][-A-Za-z0-9_.]*)?[A-Za-z0-9])$","type":"string"}},"required":["lastTransitionTime","message","reason","status","type"],"type":"object"},"type":"array"},"dispatches":{"items":{"properties":{"action":{"enum":["Observe","Demote","Promote","Fence","Follow","Rebuild","MirrorQuiesce","MirrorStop","MirrorStart","MirrorObserve"],"type":"string"},"cancelConfirmed":{"type":"boolean"},"dispatchedAt":{"format":"date-time","type":"string"},"evidenceDigest":{"type":"string"},"memberUID":{"type":"string"},"operationRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"preparedAt":{"format":"date-time","type":"string"},"terminal":{"type":"boolean"}},"required":["action","memberUID","operationRef","preparedAt"],"type":"object"},"maxItems":128,"type":"array"},"evidenceRef":{"description":"TopologyObjectReference requires the exact incarnation on every authority link.","properties":{"name":{"maxLength":253,"minLength":1,"type":"string"},"namespace":{"maxLength":63,"minLength":1,"type":"string"},"uid":{"maxLength":64,"minLength":1,"type":"string"}},"required":["name","namespace","uid"],"type":"object"},"message":{"maxLength":1024,"type":"string"},"mirrorObservation":{"properties":{"checkpointDigest":{"type":"string"},"consumerGroups":{"items":{"maxLength":255,"minLength":1,"type":"string"},"maxItems":256,"type":"array"},"destinationCommitsVerified":{"type":"boolean"},"evidenceDigest":{"type":"string"},"lagRecords":{"description":"Nil lag is unknown and cannot satisfy planned cutover.","format":"int64","minimum":0,"type":"integer"},"observedAt":{"format":"date-time","type":"string"},"sourceCommitsStopped":{"type":"boolean"},"sourceProduceZero":{"type":"boolean"},"topics":{"items":{"maxLength":249,"minLength":1,"pattern":"^[a-zA-Z0-9._-]+$","type":"string"},"maxItems":256,"type":"array"}},"required":["checkpointDigest","evidenceDigest","observedAt","topics"],"type":"object"},"observations":{"items":{"properties":{"changeUID":{"type":"string"},"demotionToken":{"description":"DemotionToken is a bounded CNPG handover token, not a SQL credential.","maxLength":16384,"type":"string"},"evidenceDigest":{"type":"string"},"memberUID":{"type":"string"},"nativeUID":{"type":"string"},"observedAt":{"format":"date-time","type":"string"},"operationUID":{"type":"string"},"promotionTokenDigest":{"maxLength":64,"type":"string"},"replayLSN":{"type":"string"},"role":{"enum":["Primary","Replica","Demoted","Fenced","Unknown"],"type":"string"},"systemIdentifier":{"maxLength":20,"type":"string"},"timeline":{"format":"int64","minimum":0,"type":"integer"}},"required":["changeUID","evidenceDigest","memberUID","nativeUID","observedAt","operationUID","role"],"type":"object"},"maxItems":32,"type":"array"},"phase":{"enum":["Preparing","Demoting","Demoted","Promoting","Fencing","Rebuilding","Quiescing","MigratingConsumers","StoppingMirror","Committed","Failed","Cancelled","RecoveryRequired"],"type":"string"},"reason":{"type":"string"},"validatedDemotionToken":{"description":"ValidatedDemotionToken is checkpointed at completed demotion; promotion\nand commit use the exact bytes after any restart.","maxLength":16384,"type":"string"}},"type":"object"},"ReplicationGroup":{"type":"object","properties":{"apiVersion":{"type":"string"},"kind":{"const":"ReplicationGroup","type":"string"},"metadata":{"$ref":"#/components/schemas/ObjectMeta"},"spec":{"$ref":"#/components/schemas/ReplicationGroupSpec"},"status":{"$ref":"#/components/schemas/ReplicationGroupStatus"}},"required":["metadata","spec","status"]},"ReplicationGroupList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ReplicationGroup"}}},"required":["items"]},"TopologyChange":{"type":"object","properties":{"apiVersion":{"type":"string"},"kind":{"const":"TopologyChange","type":"string"},"metadata":{"$ref":"#/components/schemas/ObjectMeta"},"spec":{"$ref":"#/components/schemas/TopologyChangeSpec"},"status":{"$ref":"#/components/schemas/TopologyChangeStatus"}},"required":["metadata","spec","status"]},"TopologyChangeList":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/TopologyChange"}}},"required":["items"]},"CreateReplicationGroupRequest":{"type":"object","properties":{"name":{"$ref":"#/components/schemas/ResourceName"},"idempotencyKey":{"$ref":"#/components/schemas/IdempotencyKey"},"family":{"enum":["postgresql","kafka"],"type":"string"},"mirror":{"$ref":"#/components/schemas/KafkaMirrorScope"},"mode":{"enum":["PostgresStreaming","KafkaMirror"],"type":"string"},"primary":{"description":"Primary is the desired member name, resolved inside this Project.","maxLength":63,"minLength":1,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$","type":"string"}},"required":["name","family","mode","primary"],"additionalProperties":false},"UpdateReplicationGroupRequest":{"type":"object","properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"},"primary":{"description":"Primary is the desired member name, resolved inside this Project.","maxLength":63,"minLength":1,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$","type":"string"},"mirror":{"$ref":"#/components/schemas/KafkaMirrorScope"}},"required":["uid","resourceVersion"],"additionalProperties":false},"DeleteReplicationGroupRequest":{"type":"object","properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"},"confirmation":{"type":"string"}},"required":["uid","resourceVersion","confirmation"],"additionalProperties":false},"GroupDeletionRequested":{"type":"object","properties":{"status":{"const":"DeletionRequested","type":"string"},"name":{"type":"string"},"uid":{"type":"string"}},"required":["status","name","uid"]},"ServiceReplication":{"type":"object","properties":{"groupRef":{"type":"object","properties":{"name":{"$ref":"#/components/schemas/ResourceName"}},"required":["name"],"additionalProperties":false},"replicaOptions":{"type":"object","properties":{"minApplyDelaySeconds":{"type":"integer","minimum":0,"maximum":604800}},"additionalProperties":false}},"required":["groupRef"],"additionalProperties":false},"ResourceName":{"type":"string","maxLength":253,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?(\\.[a-z0-9]([-a-z0-9]*[a-z0-9])?)*$"},"IdempotencyKey":{"type":"string","minLength":1,"maxLength":128,"description":"Generated once per user action and reused for every retry of it."},"QuoteId":{"type":"string","pattern":"^q-[0-9a-f]{32}$","description":"The id of a price quote (POST /api/billing/managed-quote) this order\naccepts. The billing service prices the order's own shape again and\nbinds it to the quote only when the operation, plan and revision, rate\ncard, storage class, member count, quantities and prices still match\nand the quote has not expired. Required when the organization's\nmanaged usage is charged (`QuoteRequired`); otherwise optional, and a\nquote that no longer holds does not block the order. A bound quote is\nrecorded on the service as `billing.kube-dc.com/quote-id`.\n"},"Error":{"type":"object","additionalProperties":false,"required":["reason","message"],"properties":{"reason":{"type":"string"},"message":{"type":"string"},"details":{"type":"object","description":"Kubernetes field causes, when Kubernetes supplied them."}}},"Status":{"type":"object","description":"A Kubernetes Status, returned by some deletions.","required":["kind"],"properties":{"kind":{"type":"string","const":"Status"}}},"ObjectMeta":{"type":"object","required":["name","uid","resourceVersion"],"properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"},"resourceVersion":{"type":"string"},"generation":{"type":"integer"},"creationTimestamp":{"type":"string"},"deletionTimestamp":{"type":"string"},"labels":{"type":"object","additionalProperties":{"type":"string"}},"annotations":{"type":"object","additionalProperties":{"type":"string"}}}},"KubernetesObject":{"type":"object","description":"A Kubernetes object as stored, for kinds whose status carries no credential or location data.","required":["metadata"],"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"$ref":"#/components/schemas/ObjectMeta"},"spec":{"type":"object"},"status":{"type":"object"}}},"InstanceMetrics":{"type":"object","additionalProperties":false,"required":["range","step","start","end","scope","series"],"properties":{"range":{"type":"string","enum":["30m","2h","24h","3d","7d"]},"step":{"type":"integer","description":"Seconds between points."},"start":{"type":"string","format":"date-time"},"end":{"type":"string","format":"date-time"},"scope":{"type":"string","enum":["local","remote"],"description":"`remote` means the instance namespace is not this cluster; no series is queried."},"series":{"type":"array","description":"CPU, memory and storage are common to every family. PostgreSQL adds connections, longestTransaction, cacheHit, transactions and replicationLag; MySQL and MariaDB add connections, queries and onlineMembers; Valkey adds connections, commands, memoryUsed and replicaLink; Kafka adds messagesIn, underReplicatedPartitions and belowMinISR; ClickHouse adds queries, activeQueries and replicationDelay. A family-specific series without samples has latest null. ReplicaLink is empty on a single-member Valkey service. Historical samples before this service UID was created are excluded.","items":{"type":"object","additionalProperties":false,"required":["key","label","unit","latest","capacity","points","available"],"properties":{"key":{"type":"string","description":"Stable metric identifier from the family set above; more may be added."},"label":{"type":"string"},"unit":{"type":"string","enum":["percent","bytes","count","per_second","seconds"]},"latest":{"type":["number","null"],"description":"The last sample, or null when the series has no samples."},"capacity":{"type":["number","null"],"description":"The matching limit in the same unit, when one is measured."},"points":{"type":"array","items":{"type":"array","prefixItems":[{"type":"number","description":"Unix seconds."},{"type":"number"}],"minItems":2,"maxItems":2}},"available":{"type":"boolean","description":"False when the query failed or the data plane is remote; distinct from an empty series."}}}}}},"ObjectList":{"type":"object","additionalProperties":false,"required":["items"],"properties":{"items":{"type":"array","items":{"type":"object"}}}},"Condition":{"type":"object","properties":{"type":{"type":"string"},"status":{"type":"string"},"reason":{"type":"string"},"message":{"type":"string"},"observedGeneration":{"type":"integer"},"lastTransitionTime":{"type":"string"}}},"RecoveryWindow":{"type":"object","additionalProperties":false,"description":"The recoverable point-in-time range a verified backup provides.","properties":{"earliest":{"type":"string"},"latest":{"type":"string"},"backupID":{"type":"string"},"backupUID":{"type":"string"},"timeline":{"type":"integer"},"engineMajor":{"type":"string"},"verifiedAt":{"type":"string"}}},"BackupSummary":{"type":"object","additionalProperties":false,"description":"A backup as observed. Object-store locations and credential references are\nnever included. `lastArchivedWALTime` is a legacy engine diagnostic, not a\npoint-in-time recovery limit.\n","properties":{"family":{"type":"string"},"format":{"type":"string"},"artifact":{"type":"object","additionalProperties":false,"required":["sha256","bytes"],"description":"Verified archive integrity; object-store paths and credentials are withheld.","properties":{"sha256":{"type":"string","pattern":"^[a-f0-9]{64}$"},"bytes":{"type":"integer","minimum":1},"payloadBytes":{"type":"integer","minimum":1,"maximum":8796093022208,"description":"Verified native OpenSearch repository bytes; bytes is the manifest length."}}},"id":{"type":"string"},"uid":{"type":"string"},"sourceUID":{"type":"string"},"phase":{"type":"string"},"startedAt":{"type":"string"},"completedAt":{"type":"string"},"engineMajor":{"type":"string"},"method":{"type":"string"},"message":{"type":"string"},"archivingHealthy":{"type":"boolean"},"firstRecoverabilityPoint":{"type":"string"},"lastArchivedWALTime":{"type":"string"},"lastSuccessfulBackupTime":{"type":"string"},"recoveryWindow":{"$ref":"#/components/schemas/RecoveryWindow"}}},"ManagedService":{"type":"object","description":"A ManagedService as stored, except that `status.lastBackup` and\n`status.recentBackups` are backup summaries. `spec` and `metadata` are not\nchanged, so a YAML view round-trips.\n","required":["metadata","spec"],"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"$ref":"#/components/schemas/ObjectMeta"},"spec":{"type":"object"},"status":{"type":"object","properties":{"lastBackup":{"anyOf":[{"$ref":"#/components/schemas/BackupSummary"},{"type":"null"}]},"recentBackups":{"type":"array","items":{"anyOf":[{"$ref":"#/components/schemas/BackupSummary"},{"type":"null"}]}}}}}},"InstanceState":{"type":"object","additionalProperties":false,"required":["phase","stale","pendingGeneration","frozen","ready","observedAt"],"description":"Presentation state. A last-known Ready badge is not shown as current when observation stopped.","properties":{"phase":{"type":"string"},"stale":{"type":"boolean"},"pendingGeneration":{"type":"boolean"},"frozen":{"type":"boolean"},"ready":{"type":"boolean"},"observedAt":{"type":["string","null"]}}},"InstanceListItem":{"allOf":[{"$ref":"#/components/schemas/ManagedService"},{"type":"object","required":["console"],"properties":{"console":{"$ref":"#/components/schemas/InstanceState"},"providerOwned":{"$ref":"#/components/schemas/ProviderOwned"}}}]},"ProviderOwned":{"type":"boolean","description":"Whether the instance is held on a provider-operated data plane. It is\nbound to the instance's immutable placement record: that record must\nname this instance and its `status.dataPlane` and have recorded an\nisolation level the platform does not treat as tenant-owned\n(NamespaceSharedNodes, NamespaceDedicatedNodes, DedicatedProviderScope)\nwith a provider placement mode, and the plane of that name must still\nbe provider-operated (such an isolation level, only provider placement\nmodes, not generated from a tenant cluster). A plane recreated or\nreclassified under the same name does not make an earlier placement\nprovider-owned. `spec.placement.mode` is the requested intent and does\nnot establish this: a ProviderDedicated placement can land on a\ndedicated cluster the tenant administers. Omitted when provenance\ncannot be established (not yet placed, no placement record, or the\nrecord or plane could not be read); clients must treat absence as\nunknown, not as provider-owned.\n"},"InstanceList":{"type":"object","additionalProperties":false,"required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/InstanceListItem"}}}},"InstanceDetail":{"type":"object","additionalProperties":false,"required":["instance","class","plan","console"],"properties":{"instance":{"$ref":"#/components/schemas/ManagedService"},"class":{"anyOf":[{"$ref":"#/components/schemas/ClassProjection"},{"type":"null"}]},"plan":{"anyOf":[{"$ref":"#/components/schemas/PlanProjection"},{"type":"null"}]},"console":{"$ref":"#/components/schemas/InstanceState"},"providerOwned":{"$ref":"#/components/schemas/ProviderOwned"},"placement":{"$ref":"#/components/schemas/InstancePlacement"},"catalogError":{"type":"object","additionalProperties":false,"required":["reason","message"],"properties":{"reason":{"type":"string"},"message":{"type":"string"}}}}},"InstancePlacement":{"type":"object","additionalProperties":false,"required":["mode","cluster","dataPlane","registration","registrationUnavailable","conditions"],"description":"Present only when `spec.placement.mode` is `TenantCluster`. `cluster`\nis the named KdcCluster, `dataPlane` the plane the hub placed the\nservice on (null before placement), `registration` that plane's\nregistration (null when unplaced, not this Project's, or unreadable;\n`registrationUnavailable` tells the last apart). `conditions` lists the\ninstance's own conditions whose reason comes from the data plane or the\ncluster placement — for example `DataPlaneRevoking` (new operations\nwait; see `registration.revocationDeadline`), `DataPlaneRetired`\n(retained in the cluster), `DataPlaneDegraded`, `PredecessorUnresolved`,\n`ClusterNotRegistered` — without messages. The full conditions stay on\n`instance.status.conditions`.\n","properties":{"mode":{"type":"string","const":"TenantCluster"},"cluster":{"type":["string","null"]},"dataPlane":{"type":["string","null"]},"registration":{"anyOf":[{"$ref":"#/components/schemas/DataPlaneRegistration"},{"type":"null"}]},"registrationUnavailable":{"type":"boolean"},"conditions":{"type":"array","items":{"$ref":"#/components/schemas/ConditionReason"}}}},"ClassOperation":{"type":"object","additionalProperties":false,"required":["type","description","destructive","parameterSchema"],"properties":{"type":{"type":"string"},"description":{"type":"string"},"destructive":{"type":"boolean"},"concurrencyClass":{"type":"string"},"parameterSchema":{"type":["object","null"]}}},"PlanOperation":{"type":"object","additionalProperties":false,"required":["type","description","destructive","parameterSchema","requiresApproval"],"properties":{"type":{"type":"string"},"description":{"type":"string"},"destructive":{"type":"boolean"},"concurrencyClass":{"type":"string"},"parameterSchema":{"type":["object","null"]},"requiresApproval":{"type":"boolean","description":"True when a provider must approve the operation before it runs."}}},"ClassProjection":{"type":"object","additionalProperties":false,"required":["name","description","ready","credentialRoles","endpointRoles","capabilities","operations"],"properties":{"name":{"type":"string"},"family":{"type":"string"},"description":{"type":"string"},"revision":{"type":"string"},"ready":{"type":"boolean"},"parameterSchema":{"type":["object","null"]},"uiContractVersion":{"type":["string","null"]},"mutationClasses":{"type":"object"},"tunables":{"type":"array","items":{"$ref":"#/components/schemas/Tunable"}},"credentialRoles":{"type":"array","items":{"type":"string"}},"credentialInputs":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["purpose","keys","required"],"properties":{"purpose":{"type":"string"},"keys":{"type":"array","items":{"type":"string"}},"required":{"type":"boolean"}}}},"endpointRoles":{"type":"array","items":{"type":"object"}},"capabilities":{"type":"array","items":{"type":"string"}},"operations":{"type":"array","items":{"$ref":"#/components/schemas/ClassOperation"}}}},"ComputeBounds":{"type":"object","additionalProperties":false,"description":"The per-instance CPU and memory range a create or Resize form may offer.","properties":{"minCPU":{"type":"string"},"maxCPU":{"type":"string"},"minMemory":{"type":"string"},"maxMemory":{"type":"string"}}},"PlanProjection":{"type":"object","additionalProperties":false,"required":["name","published","ready","capacity","credentials","backup","exposure","operations"],"properties":{"name":{"type":"string"},"className":{"type":"string"},"revision":{"type":"string"},"description":{"type":"string"},"published":{"type":"boolean"},"ready":{"type":"boolean"},"engineVersion":{"type":"string","description":"Qualified initial engine default. Kafka release lines are pinned to an exact patch; explicit Kafka choices may use other versions supported by the pinned adapter/operator. Changes require entitled upgrade operations."},"commercialTier":{"type":"string","pattern":"^[a-z][a-z0-9_]{0,22}$","maxLength":23,"description":"Optional PAYG management-fee price key. Plans with the same key share a fixed fee; a different fee uses another key. This does not activate charging or replace quote qualification."},"capacity":{"type":"object","additionalProperties":false,"properties":{"cpu":{"type":"string"},"memory":{"type":"string"},"storage":{"type":"string"},"maxStorage":{"type":"string"},"storageClass":{"type":"string"},"storageRole":{"type":"string","minLength":1,"maxLength":63,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$","description":"Logical role resolved by the selected site at placement. Omit instance storage.class for these plans; the resolved physical class is immutable."},"storageAllocationMode":{"type":"string","enum":["Volume","UnrestrictedLocal"],"description":"Physical volume expansion or recorded allocation growth on qualified unrestricted local HA storage."},"sizeMeaning":{"type":"string","enum":["volume","allocation"]},"filesystemLimitEnforced":{"type":"boolean","description":"False for unrestricted local storage; declared allocation does not cap filesystem usage."},"allowedStorageClasses":{"type":"array","items":{"type":"string"}},"computeBounds":{"$ref":"#/components/schemas/ComputeBounds"}}},"topology":{"$ref":"#/components/schemas/Topology"},"tunables":{"type":"array","items":{"$ref":"#/components/schemas/Tunable"}},"declarativeChanges":{"type":"boolean"},"minIsolation":{"type":"string"},"placementModes":{"type":"array","items":{"type":"string"}},"connectivityClasses":{"type":"array","items":{"type":"string"}},"deletionPolicies":{"type":"array","items":{"type":"string"}},"allowedImages":{"type":"array","items":{"type":"string"}},"support":{"type":"object","additionalProperties":false,"properties":{"tier":{"type":"string"},"responsibilityText":{"type":"string"}}},"credentials":{"type":"object","additionalProperties":false,"required":["allowExistingUsers","allowManagedSecretDelivery","allowDatabaseEngine","allowDynamicDatabaseCredentials"],"properties":{"allowExistingUsers":{"type":"boolean"},"allowManagedSecretDelivery":{"type":"boolean"},"allowDatabaseEngine":{"type":"boolean"},"allowDynamicDatabaseCredentials":{"type":"boolean"}}},"backup":{"type":"object","additionalProperties":false,"required":["enabled","pitr","customStores","allowedCustomEndpoints"],"properties":{"enabled":{"type":"boolean"},"schedule":{"type":"string"},"credentialDelivery":{"type":"string","enum":["Secret","OpenBaoReference"]},"retentionDays":{"type":["integer","null"]},"pitr":{"type":"boolean"},"minRetentionDays":{"type":["integer","null"]},"maxRetentionDays":{"type":["integer","null"]},"minScheduleIntervalMinutes":{"type":["integer","null"]},"customStores":{"type":"boolean"},"allowedCustomEndpoints":{"type":"array","items":{"type":"string"}}}},"exposure":{"type":"object","additionalProperties":false,"required":["allowPublicLoadBalancer","gatewayAvailable"],"description":"Entitlements only; gateway coordinates are provider internals.","properties":{"allowPublicLoadBalancer":{"type":"boolean"},"gatewayAvailable":{"type":"boolean"}}},"maintenance":{"anyOf":[{"$ref":"#/components/schemas/Maintenance"},{"type":"null"}]},"maxInstancesPerProject":{"type":"integer"},"operations":{"type":"array","items":{"$ref":"#/components/schemas/PlanOperation"}},"replication":{"type":"object","properties":{"mode":{"enum":["PostgresStreaming","KafkaMirror"],"type":"string"},"maxMembers":{"type":"integer"},"allowCrossSite":{"type":"boolean"},"allowEmergencyFailover":{"type":"boolean"}}}}},"Topology":{"type":"object","additionalProperties":false,"description":"The bounds a plan offers, in exactly one shape: the instance fields for a member-counted family, the shard fields for a sharded one, or dataReplicas for an OpenSearch data pool. The shapes are exclusive.","properties":{"minInstances":{"type":"integer"},"maxInstances":{"type":"integer"},"defaultInstances":{"type":"integer"},"minDataReplicas":{"type":"integer"},"maxDataReplicas":{"type":"integer"},"defaultDataReplicas":{"type":"integer"},"minShards":{"type":"integer"},"maxShards":{"type":"integer"},"defaultShards":{"type":"integer"},"minReplicasPerShard":{"type":"integer"},"maxReplicasPerShard":{"type":"integer"},"defaultReplicasPerShard":{"type":"integer"},"ha":{"type":"boolean"},"synchronousStandbys":{"type":"integer","minimum":0,"maximum":8},"durability":{"type":"string","enum":["preferred","required"]}}},"Maintenance":{"type":"object","additionalProperties":false,"required":["day","startHour","durationMinutes"],"properties":{"day":{"type":"string","enum":["Any","Mon","Tue","Wed","Thu","Fri","Sat","Sun"]},"startHour":{"type":"integer","minimum":0,"maximum":23},"durationMinutes":{"type":"integer","minimum":30,"maximum":1440}}},"ConnectivityClass":{"type":"object","additionalProperties":false,"required":["name","description","protocols"],"properties":{"name":{"type":"string"},"description":{"type":"string"},"reachability":{"type":"string"},"direction":{"type":"string"},"isolation":{"type":"string"},"protocols":{"type":"array","items":{"type":"string"}},"tls":{"type":"string"},"endpointCardinality":{"type":"string"}}},"Permissions":{"type":"object","additionalProperties":false,"description":"Access-review hints for the caller. Kubernetes still decides every write.","required":["create","configure","delete","operate","bind","managePolicies","editPolicies","deletePolicies","readBackups","createGrant"],"properties":{"createGrant":{"type":"boolean","description":"May grant a Project cluster to run services (`POST /{namespace}/data-planes/{name}/grant` also needs patch on the cluster)."},"create":{"type":"boolean"},"configure":{"type":"boolean"},"delete":{"type":"boolean"},"operate":{"type":"boolean"},"bind":{"type":"boolean"},"managePolicies":{"type":"boolean"},"editPolicies":{"type":"boolean"},"deletePolicies":{"type":"boolean"},"readBackups":{"type":"boolean"}}},"Catalog":{"type":"object","additionalProperties":false,"required":["contractVersion","classes","plans","connectivityClasses","permissions","unavailableOffers"],"properties":{"contractVersion":{"type":"string","const":"v1"},"classes":{"type":"array","items":{"$ref":"#/components/schemas/ClassProjection"}},"plans":{"type":"array","items":{"$ref":"#/components/schemas/PlanProjection"}},"connectivityClasses":{"type":"array","items":{"$ref":"#/components/schemas/ConnectivityClass"}},"permissions":{"$ref":"#/components/schemas/Permissions"},"unavailableOffers":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["family","reason"],"properties":{"family":{"type":"string"},"reason":{"type":"string"}}}}}},"OperationReference":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"}}},"CredentialPolicy":{"type":"object","additionalProperties":false,"required":["metadata","spec","status"],"properties":{"metadata":{"type":"object","additionalProperties":false,"required":["name","uid","resourceVersion"],"properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"},"resourceVersion":{"type":"string"},"generation":{"type":"integer"},"creationTimestamp":{"type":"string"},"deletionTimestamp":{"type":"string"}}},"spec":{"type":"object","required":["serviceRef","serviceUID"],"properties":{"serviceRef":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"serviceUID":{"type":"string"},"role":{"type":"string"},"existingUser":{"type":"object","properties":{"username":{"type":"string"},"database":{"type":"string"}}},"rotationIntervalSeconds":{"type":"integer"},"paused":{"type":"boolean"}}},"status":{"type":"object","additionalProperties":false,"properties":{"credentialRole":{"type":"string"},"observedGeneration":{"type":"integer"},"sequence":{"type":"integer"},"activeOperation":{"$ref":"#/components/schemas/OperationReference"},"lastOperation":{"$ref":"#/components/schemas/OperationReference"},"lastAttemptAt":{"type":"string"},"lastRotationAt":{"type":"string"},"nextRotationAt":{"type":"string"},"conditions":{"type":"array","items":{"$ref":"#/components/schemas/Condition"}}}}}},"CredentialPolicyList":{"type":"object","additionalProperties":false,"required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/CredentialPolicy"}}}},"BackupRecord":{"type":"object","additionalProperties":false,"required":["metadata","spec","status"],"properties":{"metadata":{"type":"object","additionalProperties":false,"required":["name","uid","resourceVersion"],"properties":{"name":{"type":"string"},"uid":{"type":"string"},"resourceVersion":{"type":"string"},"generation":{"type":"integer"},"creationTimestamp":{"type":"string"}}},"spec":{"type":"object","additionalProperties":false,"properties":{"origin":{"type":"string"},"className":{"type":"string"},"planName":{"type":"string"},"backupName":{"type":"string"},"serviceRef":{"type":"object","additionalProperties":false,"properties":{"name":{"type":"string"}}},"serviceUID":{"type":"string"}}},"status":{"type":"object","additionalProperties":false,"required":["backup"],"properties":{"observedAt":{"type":"string"},"recordedAt":{"type":"string"},"recovery":{"$ref":"#/components/schemas/RecoveryAvailability"},"backup":{"anyOf":[{"$ref":"#/components/schemas/BackupSummary"},{"type":"null"}]}}},"sourcePlacement":{"$ref":"#/components/schemas/BackupSourcePlacement"}}},"BackupSourcePlacement":{"description":"Where the backup's source service ran, resolved from the data plane the\nrecord names and pins by UID, so it stays authoritative after the\nsource service is deleted. `TenantCluster` names the Project KdcCluster\nthe registrar generated that plane from (the name is kept even when the\nKdcCluster has since been deleted); a restore of such a backup must\ntarget that cluster. The lock names the cluster, not its\nincarnation: a KdcCluster deleted and recreated under the same name\nmatches it, and the hub revalidates the restore against the original\nsource plane. `Provider` is a provider-operated plane: an isolation\nlevel the hub does not treat as tenant-owned (NamespaceSharedNodes,\nNamespaceDedicatedNodes, DedicatedProviderScope) and only provider\nplacement modes. The field is omitted when the placement cannot be\ndetermined (the plane is gone, the name now refers to another plane\nincarnation, the plane names another Project, the plane is an\noperator-registered tenant-owned plane without a registrar source,\nthe plane has no provider evidence, or it could not be read);\nclients must treat absence as unknown and not offer a restore target\non that basis.\n","oneOf":[{"type":"object","additionalProperties":false,"required":["mode","clusterRef"],"properties":{"mode":{"type":"string","const":"TenantCluster"},"clusterRef":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"type":"string","minLength":1,"maxLength":253}}}}},{"type":"object","additionalProperties":false,"required":["mode"],"properties":{"mode":{"type":"string","const":"Provider"}}}]},"BackupRecordList":{"type":"object","additionalProperties":false,"required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/BackupRecord"}}}},"RevealResponse":{"type":"object","additionalProperties":false,"required":["secretName","namespace","data","encoding"],"properties":{"secretName":{"type":"string"},"namespace":{"type":"string"},"encoding":{"type":"string","const":"base64"},"data":{"type":"object","additionalProperties":{"type":"string"}}}},"PinnedRequest":{"type":"object","additionalProperties":false,"required":["uid","resourceVersion"],"properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"}}},"Tunable":{"type":"object","additionalProperties":false,"required":["path","type","disruptive"],"properties":{"path":{"type":"string"},"type":{"type":"string","enum":["string","integer","quantity","enum","boolean"]},"disruptive":{"type":"boolean"},"values":{"type":"array","items":{"type":"string"}},"bounds":{"type":"object","additionalProperties":{"type":"string"}},"description":{"type":"string"}}},"ServiceCompute":{"type":"object","additionalProperties":false,"properties":{"cpu":{"type":"string","minLength":1,"maxLength":253},"memory":{"type":"string","minLength":1,"maxLength":253}}},"ServiceStorage":{"type":"object","additionalProperties":false,"properties":{"size":{"type":"string","minLength":1,"maxLength":253},"class":{"type":"string","minLength":1,"maxLength":253,"description":"Qualified storage class; immutable after creation."}}},"ServiceTopology":{"type":"object","additionalProperties":false,"description":"The size of a service in the shape its plan offers. A member-counted family sets instances; a sharded family (ClickHouse) sets shards and replicasPerShard and refuses instances, because one number cannot say whether a change copies data or divides it. OpenSearch sets only dataReplicas; its three dedicated cluster managers are fixed provider overhead. The three shapes are never combined in one request.","properties":{"instances":{"type":"integer","minimum":1,"maximum":1000,"description":"Total PostgreSQL members, Kafka brokers, or Valkey members."},"dataReplicas":{"type":"integer","minimum":1,"maximum":64,"description":"OpenSearch data nodes, bounded by the plan; excludes dedicated cluster managers."},"shards":{"type":"integer","minimum":1,"maximum":64,"description":"Independent data shards. Fixed at creation until a resharding operation moves historical data."},"replicasPerShard":{"type":"integer","minimum":1,"maximum":16,"description":"Replicas inside every shard. Coordination members (ClickHouse Keeper) are provider-owned and reported in status, never requested."}}},"ServiceMaintenance":{"type":"object","additionalProperties":false,"properties":{"applyImmediately":{"type":"boolean","description":"Bypass the maintenance window, retaining approval requirements."},"window":{"allOf":[{"$ref":"#/components/schemas/Maintenance"}],"description":"Recurring UTC window selected for this service; defaults to the plan window when omitted."}}},"CreateInstanceRequest":{"type":"object","additionalProperties":false,"required":["name","spec"],"properties":{"name":{"$ref":"#/components/schemas/ResourceName"},"idempotencyKey":{"$ref":"#/components/schemas/IdempotencyKey"},"quoteId":{"$ref":"#/components/schemas/QuoteId"},"catalogRevisions":{"type":"object","additionalProperties":false,"required":["classRevision","planRevision"],"description":"Optional create-sheet precondition. If either displayed catalog revision changed, the server returns 409 CatalogChanged before writing a service.","properties":{"classRevision":{"type":"string","minLength":1,"maxLength":128},"planRevision":{"type":"string","minLength":1,"maxLength":128}}},"spec":{"type":"object","additionalProperties":false,"required":["classRef","planRef"],"properties":{"classRef":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"planRef":{"type":"object","required":["name"],"properties":{"name":{"type":"string"}}},"compute":{"$ref":"#/components/schemas/ServiceCompute"},"storage":{"$ref":"#/components/schemas/ServiceStorage"},"topology":{"$ref":"#/components/schemas/ServiceTopology"},"maintenance":{"$ref":"#/components/schemas/ServiceMaintenance"},"engineVersion":{"type":"string","maxLength":64},"retry":{"type":"string","maxLength":64},"parameters":{"type":"object","description":"Engine parameters validated by the class schema. Platform capacity, topology and version use their typed fields.","not":{"anyOf":[{"required":["cpu"]},{"required":["memory"]},{"required":["instances"]},{"required":["storage"]},{"required":["storageSize"]},{"required":["version"]}]}},"placement":{"$ref":"#/components/schemas/PlacementRequest"},"connectivity":{"type":"object"},"deletionPolicy":{"type":"string","enum":["Retain","Delete","SnapshotAndDelete"]},"deletionProtection":{"type":"boolean"},"replication":{"$ref":"#/components/schemas/ServiceReplication"}}}}},"DataPlaneFamilies":{"type":"array","items":{"type":"string","pattern":"^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$"}},"NullableTimestamp":{"type":["string","null"],"description":"RFC 3339 time, or null."},"DataPlaneGrant":{"type":"object","additionalProperties":false,"required":["name","uid","clusterUID","currentIncarnation","families","disclosure","phase","reason","generation","dataPlane","deleting","createdAt"],"description":"A ServiceDataPlaneGrant. The spec is the Project admin's; phase, reason, generation and dataPlane are the hub's verdict.","properties":{"name":{"type":"string"},"uid":{"type":"string"},"clusterUID":{"type":["string","null"],"description":"The KdcCluster UID the grant names."},"currentIncarnation":{"type":["boolean","null"],"description":"Whether the grant names the cluster's live UID; null when the cluster was not read."},"families":{"$ref":"#/components/schemas/DataPlaneFamilies"},"disclosure":{"type":["string","null"],"enum":["ProjectCredentialsToClusterAdministrators",null]},"phase":{"type":["string","null"],"enum":["Pending","Bound","Refused","Consumed",null]},"reason":{"type":["string","null"],"enum":["DuplicateGrant","NotAfterWatermark","AmbiguousGrants","FamiliesNarrower","IncarnationMismatch","Terminating",null]},"generation":{"type":["integer","null"],"description":"The registration generation the grant served (set once)."},"dataPlane":{"type":["string","null"]},"deleting":{"type":"boolean"},"createdAt":{"$ref":"#/components/schemas/NullableTimestamp"}}},"DataPlaneRegistration":{"type":"object","additionalProperties":false,"required":["dataPlane","phase","reason","generation","grantUID","grantWatermark","revocationDeadline","revocationCause","deleting","ready","families"],"description":"The registration of the hub-generated data plane. `Revoking` keeps\nexisting instances running until `revocationDeadline` (72 hours by\ndefault after the grant was deleted or the opt-in removed); a new grant\nand the opt-in before then reinstate the same generation.\n","properties":{"dataPlane":{"type":"string"},"phase":{"type":["string","null"],"enum":["Bootstrapping","Active","Suspended","Revoking","RetiringHeld","Retired","PlaneLost",null]},"reason":{"type":["string","null"]},"generation":{"type":["integer","null"]},"grantUID":{"type":["string","null"]},"grantWatermark":{"description":"Grants created at or before this time can no longer register this plane (the hub's registration watermark); null when none is recorded.","$ref":"#/components/schemas/NullableTimestamp"},"revocationDeadline":{"$ref":"#/components/schemas/NullableTimestamp"},"revocationCause":{"type":["string","null"],"enum":["AnnotationRemoved","GrantDeleting","GrantNotFound",null]},"deleting":{"type":"boolean"},"ready":{"type":"boolean"},"families":{"$ref":"#/components/schemas/DataPlaneFamilies"}}},"ConditionReason":{"type":"object","additionalProperties":false,"required":["type","status","reason"],"description":"A condition without its message.","properties":{"type":{"type":["string","null"]},"status":{"type":"string","enum":["True","False","Unknown"]},"reason":{"type":["string","null"]}}},"DataPlaneEligibility":{"type":"object","additionalProperties":false,"required":["eligible","reason"],"description":"Whether a service can be placed on the cluster now. `reason`, first\nmatch wins: ClusterDeleting, NotOptedIn, NoFamilies, NameTooLong,\nClusterAPIDisabled; with a data plane: DataPlaneDeleting,\nRegistrationPending, Registration<Phase> (for example\nRegistrationRevoking), NotAcceptingPlacements, NoOfferedFamily, or\nAcceptingPlacements (eligible); without one: AmbiguousGrants,\nRegistrationPending (one eligible grant, the hub has not registered it\nyet), AwaitingGrant, GrantIncarnationMismatch, GrantDeleting,\nGrantConsumed, GrantFamiliesNarrower.\n","properties":{"eligible":{"type":"boolean"},"reason":{"type":"string"}}},"DataPlaneCluster":{"type":"object","additionalProperties":false,"required":["name","uid","resourceVersion","phase","deleting","clusterAPI","optIn","grant","grants","registration","fitness","eligibility"],"properties":{"name":{"type":"string"},"uid":{"type":"string"},"resourceVersion":{"type":"string"},"phase":{"type":["string","null"],"description":"The KdcCluster phase."},"deleting":{"type":"boolean"},"clusterAPI":{"type":"boolean","description":"spec.enableClusterAPI; registration needs it."},"optIn":{"$ref":"#/components/schemas/DataPlaneOptIn"},"grant":{"description":"The grant the registration is bound to, else the grant named after the cluster, else the newest naming its live UID.","anyOf":[{"$ref":"#/components/schemas/DataPlaneGrant"},{"type":"null"}]},"grants":{"type":"array","description":"Every grant naming this cluster, any incarnation.","items":{"$ref":"#/components/schemas/DataPlaneGrant"}},"registration":{"anyOf":[{"$ref":"#/components/schemas/DataPlaneRegistration"},{"type":"null"}]},"fitness":{"type":"array","items":{"$ref":"#/components/schemas/ConditionReason"}},"eligibility":{"$ref":"#/components/schemas/DataPlaneEligibility"}}},"DataPlaneOptIn":{"type":"object","additionalProperties":false,"required":["enabled","value","families"],"description":"The opt-in annotations `services.kube-dc.com/data-plane` and `services.kube-dc.com/families`.","properties":{"enabled":{"type":"boolean"},"value":{"type":["string","null"]},"families":{"$ref":"#/components/schemas/DataPlaneFamilies"}}},"DataPlanePermissions":{"type":"object","additionalProperties":false,"required":["createGrant","deleteGrant","patchCluster"],"description":"Access-review hints. Granting needs createGrant and patchCluster (the Project admin role).","properties":{"createGrant":{"type":"boolean"},"deleteGrant":{"type":"boolean"},"patchCluster":{"type":"boolean"}}},"DataPlaneList":{"type":"object","additionalProperties":false,"required":["families","served","permissions","items"],"properties":{"families":{"$ref":"#/components/schemas/DataPlaneFamilies"},"served":{"type":"object","additionalProperties":false,"required":["kdcClusters","grants","dataPlanes"],"properties":{"kdcClusters":{"type":"boolean"},"grants":{"type":"boolean"},"dataPlanes":{"type":"boolean"}}},"permissions":{"$ref":"#/components/schemas/DataPlanePermissions"},"items":{"type":"array","items":{"$ref":"#/components/schemas/DataPlaneCluster"}}}},"CreateDataPlaneGrantRequest":{"type":"object","additionalProperties":false,"required":["families","acknowledgeDisclosure"],"properties":{"families":{"type":"array","minItems":1,"maxItems":16,"uniqueItems":true,"description":"Service families the cluster may serve; each must be in the data-planes `families` list.","items":{"type":"string","pattern":"^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$"}},"acknowledgeDisclosure":{"type":"boolean","const":true,"description":"Credentials of services on this cluster, and the Project backup bucket key, become readable by the cluster administrators."}}},"DeleteDataPlaneGrantRequest":{"type":"object","additionalProperties":false,"required":["uid","confirm"],"properties":{"uid":{"type":"string","minLength":1,"maxLength":64,"description":"The uid of the reviewed grant."},"confirm":{"type":"string","description":"The cluster name, typed to confirm."}}},"DataPlaneGrantResult":{"type":"object","additionalProperties":false,"required":["created","grant","optIn"],"properties":{"created":{"type":"boolean"},"grant":{"$ref":"#/components/schemas/DataPlaneGrant"},"optIn":{"$ref":"#/components/schemas/DataPlaneOptIn"}}},"DataPlaneGrantCheck":{"description":"The decision of a grant request, from `POST /{namespace}/data-planes/{name}/grant/check`.","oneOf":[{"$ref":"#/components/schemas/DataPlaneGrantCheckReuse"},{"$ref":"#/components/schemas/DataPlaneGrantCheckCreate"},{"$ref":"#/components/schemas/DataPlaneGrantCheckRefuse"}],"discriminator":{"propertyName":"decision","mapping":{"reuse":"#/components/schemas/DataPlaneGrantCheckReuse","create":"#/components/schemas/DataPlaneGrantCheckCreate","refuse":"#/components/schemas/DataPlaneGrantCheckRefuse"}}},"DataPlaneOptInAnnotations":{"description":"The opt-in annotations the request would set, or null when the cluster is already opted in for these families.","anyOf":[{"type":"object","additionalProperties":false,"required":["services.kube-dc.com/data-plane","services.kube-dc.com/families"],"properties":{"services.kube-dc.com/data-plane":{"type":"string","enum":["enabled"]},"services.kube-dc.com/families":{"type":"string"}}},{"type":"null"}]},"DataPlaneGrantCheckReuse":{"type":"object","additionalProperties":false,"required":["decision","families","grantName","grantUID","grant","optIn","optInAnnotations"],"description":"The request would reuse the existing grant `grantName` (the grant POST answers 200, `created` false).","properties":{"decision":{"type":"string","enum":["reuse"]},"families":{"$ref":"#/components/schemas/DataPlaneFamilies"},"grantName":{"type":"string"},"grantUID":{"type":"string"},"grant":{"$ref":"#/components/schemas/DataPlaneGrant"},"optIn":{"$ref":"#/components/schemas/DataPlaneOptIn"},"optInAnnotations":{"$ref":"#/components/schemas/DataPlaneOptInAnnotations"}}},"DataPlaneGrantCheckCreate":{"type":"object","additionalProperties":false,"required":["decision","families","grantName","optIn","optInAnnotations"],"description":"The request would create the grant `grantName`, the cluster name (the grant POST answers 201).","properties":{"decision":{"type":"string","enum":["create"]},"families":{"$ref":"#/components/schemas/DataPlaneFamilies"},"grantName":{"type":"string"},"optIn":{"$ref":"#/components/schemas/DataPlaneOptIn"},"optInAnnotations":{"$ref":"#/components/schemas/DataPlaneOptInAnnotations"}}},"DataPlaneGrantCheckRefuse":{"type":"object","additionalProperties":false,"required":["decision","families","reason","message"],"description":"The grant POST would answer 409 with `reason` and `message`.","properties":{"decision":{"type":"string","enum":["refuse"]},"families":{"$ref":"#/components/schemas/DataPlaneFamilies"},"reason":{"type":"string","enum":["FamilyNotOffered","ClusterDeleting","GrantConflict","GrantDeleting","ReplacementGrantRequired"]},"message":{"type":"string"}}},"LocalObjectReference":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"$ref":"#/components/schemas/ResourceName"}}},"PlacementRequest":{"type":"object","additionalProperties":false,"required":["mode"],"description":"Where the service runs. `TenantCluster` places it on one of this\nProject's managed clusters and must name that cluster in `clusterRef`\n(400 `ClusterRefRequired` otherwise); the cluster must exist in the\nProject (400 `ClusterNotFound`) and not be deleting (409\n`ClusterDeleting`). The cluster serves services only after a Project\nadmin granted it (`POST /{namespace}/data-planes/{name}/grant`); until\nits registration is Active the service waits with a named placement\nreason. `clusterRef` is refused with any other mode and together with\n`dataPlaneRef`. Placement is immutable after creation.\n","properties":{"mode":{"type":"string","enum":["ProviderShared","ProviderDedicated","TenantCluster","BYOCluster"]},"dataPlaneRef":{"$ref":"#/components/schemas/LocalObjectReference"},"clusterRef":{"$ref":"#/components/schemas/LocalObjectReference"},"siteSelector":{"type":"object","additionalProperties":false,"properties":{"matchLabels":{"type":"object","additionalProperties":{"type":"string"}},"matchExpressions":{"type":"array","items":{"type":"object","additionalProperties":false,"required":["key","operator"],"properties":{"key":{"type":"string","minLength":1},"operator":{"type":"string","enum":["In","NotIn","Exists","DoesNotExist"]},"values":{"type":"array","items":{"type":"string"}}}}}}}},"allOf":[{"if":{"required":["clusterRef"]},"then":{"properties":{"mode":{"const":"TenantCluster"}},"not":{"required":["dataPlaneRef"]}}},{"if":{"required":["mode"],"properties":{"mode":{"const":"TenantCluster"}}},"then":{"required":["clusterRef"]}}]},"UpdateInstanceRequest":{"type":"object","additionalProperties":false,"required":["uid","resourceVersion"],"properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"},"quoteId":{"allOf":[{"$ref":"#/components/schemas/QuoteId"}],"description":"Cited only by a change of compute, storage or topology (a resize)."},"compute":{"$ref":"#/components/schemas/ServiceCompute"},"storage":{"$ref":"#/components/schemas/ServiceStorage"},"topology":{"$ref":"#/components/schemas/ServiceTopology"},"maintenance":{"$ref":"#/components/schemas/ServiceMaintenance"},"engineVersion":{"type":"string","maxLength":64},"retry":{"type":"string","maxLength":64},"parameters":{"type":"object","description":"The complete engine parameter object; a missing key is removed. Platform capacity, topology and version use their typed fields.","not":{"anyOf":[{"required":["cpu"]},{"required":["memory"]},{"required":["instances"]},{"required":["storage"]},{"required":["storageSize"]},{"required":["version"]}]}},"deletionProtection":{"type":"boolean"},"deletionPolicy":{"type":"string","enum":["Retain","Delete","SnapshotAndDelete"]}}},"DeleteInstanceRequest":{"type":"object","additionalProperties":false,"required":["uid","confirmation"],"oneOf":[{"required":["generation"]},{"required":["resourceVersion"]}],"properties":{"uid":{"type":"string"},"generation":{"type":"integer","minimum":1,"description":"The spec generation displayed when deletion was confirmed."},"resourceVersion":{"type":"string","description":"Existing v1 clients only; must match at the initial read."},"confirmation":{"type":"string","description":"The service name, typed by the user."}}},"CreateRestoreRequest":{"type":"object","additionalProperties":false,"required":["serviceRef","serviceUID","idempotencyKey","restore"],"properties":{"serviceRef":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"$ref":"#/components/schemas/ResourceName"}}},"serviceUID":{"type":"string","minLength":1,"maxLength":64},"idempotencyKey":{"$ref":"#/components/schemas/IdempotencyKey"},"restore":{"type":"object","additionalProperties":false,"required":["backupRef","target"],"properties":{"backupRef":{"type":"object","additionalProperties":false,"required":["name","uid"],"properties":{"name":{"$ref":"#/components/schemas/ResourceName"},"uid":{"type":"string","minLength":1,"maxLength":64}}},"targetTime":{"type":"string","format":"date-time","pattern":"^[0-9]{4}-[0-9]{2}-[0-9]{2}T[0-9]{2}:[0-9]{2}:[0-9]{2}(Z|[+-][0-9]{2}:[0-9]{2})$","description":"PostgreSQL only. Whole-second RFC3339 time within this exact backup recovery window. Valkey restores the selected snapshot without targetTime."},"target":{"type":"object","additionalProperties":false,"required":["name","planRef","engineVersion","placement","connectivity"],"properties":{"name":{"$ref":"#/components/schemas/ResourceName"},"planRef":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"$ref":"#/components/schemas/ResourceName"}}},"engineVersion":{"type":"string","pattern":"^[1-9][0-9]*[.][0-9]+([.][0-9]+){0,2}$"},"compute":{"$ref":"#/components/schemas/ServiceCompute"},"storage":{"$ref":"#/components/schemas/ServiceStorage"},"topology":{"$ref":"#/components/schemas/ServiceTopology"},"parameters":{"type":"object"},"placement":{"$ref":"#/components/schemas/PlacementRequest"},"connectivity":{"type":"object","additionalProperties":false,"required":["classRef"],"properties":{"classRef":{"type":"object","additionalProperties":false,"required":["name"],"properties":{"name":{"$ref":"#/components/schemas/ResourceName"}}}}},"maintenance":{"$ref":"#/components/schemas/ServiceMaintenance"}}}}},"execution":{"type":"object","additionalProperties":false,"properties":{"window":{"type":"string","enum":["Immediate","NextPlanWindow"]}}}}},"RecoveryAvailability":{"type":"object","additionalProperties":false,"properties":{"family":{"type":"string"},"format":{"type":"string"},"retainUntil":{"type":"string"}}},"CreateOperationRequest":{"type":"object","additionalProperties":false,"required":["uid","resourceVersion","type","idempotencyKey"],"properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"},"type":{"type":"string","description":"An operation the plan allows and the class declares a parameter schema for, excluding RestoreToNew (use the Project restores endpoint)."},"idempotencyKey":{"$ref":"#/components/schemas/IdempotencyKey"},"parameters":{"type":"object"},"execution":{"type":"object","additionalProperties":false,"properties":{"window":{"type":"string","enum":["Immediate","NextPlanWindow"]}}},"quoteId":{"allOf":[{"$ref":"#/components/schemas/QuoteId"}],"description":"Cited only by Resize, ExpandStorage or Scale, whose resulting shape is checked as a resize order (PAYG P40)."}}},"CreateBindingRequest":{"type":"object","additionalProperties":false,"required":["uid","name","role"],"properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string","description":"Optional caller observation; binding creation does not require it to match. The immutable service UID is the identity precondition."},"name":{"$ref":"#/components/schemas/ResourceName"},"role":{"type":"string","description":"A class-declared role, or the `status.credentialRole` of an existing-user policy of this instance."},"databaseCredentials":{"$ref":"#/components/schemas/DatabaseCredentialOptions"},"deliveryMode":{"type":"string","enum":["DataPlaneLocalSecret","ManagedSecret","OpenBao"],"default":"DataPlaneLocalSecret"},"secretName":{"$ref":"#/components/schemas/ResourceName"},"endpointName":{"type":"string"},"idempotencyKey":{"$ref":"#/components/schemas/IdempotencyKey"}}},"CreateCredentialPolicyRequest":{"type":"object","additionalProperties":false,"required":["uid","resourceVersion","name"],"oneOf":[{"required":["role"]},{"required":["existingUser"]}],"properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"},"name":{"$ref":"#/components/schemas/ResourceName"},"role":{"type":"string","minLength":1,"maxLength":63,"description":"A declared credential role; not an `existing-` or `sql-user:` role."},"existingUser":{"type":"object","additionalProperties":false,"required":["username","database"],"properties":{"username":{"type":"string","minLength":1,"maxLength":63},"database":{"type":"string","minLength":1,"maxLength":63}}},"rotationIntervalSeconds":{"type":"integer","minimum":60,"maximum":31536000,"description":"Defaults to 2592000 (30 days) when omitted."},"paused":{"type":"boolean"},"idempotencyKey":{"$ref":"#/components/schemas/IdempotencyKey"}}},"UpdateCredentialPolicyRequest":{"type":"object","additionalProperties":false,"required":["uid","resourceVersion"],"anyOf":[{"required":["rotationIntervalSeconds"]},{"required":["paused"]}],"properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"},"rotationIntervalSeconds":{"type":"integer","minimum":60,"maximum":31536000},"paused":{"type":"boolean"}}},"DatabaseCredentialOptions":{"type":"object","additionalProperties":false,"properties":{"mode":{"type":"string","enum":["Static","Dynamic"],"default":"Static"},"rotationPeriodSeconds":{"type":"integer","minimum":60,"maximum":31536000,"default":86400},"defaultTTLSeconds":{"type":"integer","minimum":60,"maximum":86400,"default":3600},"maxTTLSeconds":{"type":"integer","minimum":60,"maximum":604800,"default":86400}}},"DatabaseLeaseRevokeRequest":{"type":"object","additionalProperties":false,"required":["uid","resourceVersion","leaseId"],"properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"},"leaseId":{"type":"string","maxLength":2048}}},"DatabaseLeaseRenewRequest":{"type":"object","additionalProperties":false,"required":["uid","resourceVersion","leaseId"],"properties":{"uid":{"type":"string"},"resourceVersion":{"type":"string"},"leaseId":{"type":"string","maxLength":2048},"incrementSeconds":{"type":"integer","minimum":60,"maximum":604800}}},"DatabaseLease":{"type":"object","additionalProperties":false,"required":["leaseId","leaseDurationSeconds","renewable"],"properties":{"leaseId":{"type":"string"},"leaseDurationSeconds":{"type":"integer","minimum":1,"maximum":604800},"renewable":{"type":"boolean"}}},"DatabaseLeaseIssued":{"type":"object","additionalProperties":false,"required":["credentials","leaseId","leaseDurationSeconds","renewable"],"properties":{"leaseId":{"type":"string"},"leaseDurationSeconds":{"type":"integer","minimum":1,"maximum":604800},"renewable":{"type":"boolean"},"credentials":{"type":"object","additionalProperties":false,"required":["username","password","host","port","database","uri","ca.crt"],"properties":{"username":{"type":"string"},"password":{"type":"string"},"host":{"type":"string"},"port":{"type":"string"},"database":{"type":"string"},"uri":{"type":"string"},"ca.crt":{"type":"string"}}}}},"SettlementPeriodView":{"type":"object","required":["periodId","accountId","organizationUid","state","currency","windowStart","windowEnd","completenessCutoff","unresolvedGaps","unpricedComponents","total"],"properties":{"periodId":{"type":"string"},"accountId":{"type":"string"},"organizationUid":{"type":"string"},"state":{"enum":["open","closing","validated","finalized","exported","acknowledged","failed"]},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"windowStart":{"type":"string","format":"date-time"},"windowEnd":{"type":"string","format":"date-time"},"completenessCutoff":{"type":"string","format":"date-time"},"unresolvedGaps":{"type":"integer","minimum":0},"unpricedComponents":{"type":"array","items":{"type":"string"}},"waiverReason":{"type":"string"},"waivedBy":{"type":"string"},"total":{"type":["string","null"],"description":"Exact decimal; null until the period is finalized."},"ratingRunId":{"type":"string"},"finalizedAt":{"type":"string","format":"date-time"},"finalizedBy":{"type":"string"},"invoiceRef":{"type":"string"},"acknowledgedAt":{"type":"string","format":"date-time"}}},"Decimal":{"type":"string","pattern":"^-?(?:\\d+|\\d+\\.\\d+)$","maxLength":64,"description":"An exact decimal. A JSON number is rejected: 0.00003 is not\nrepresentable in IEEE-754, and byte-seconds for a terabyte-month exceed\n2^53.\n"},"NullableDecimal":{"oneOf":[{"$ref":"#/components/schemas/Decimal"},{"type":"null"}],"description":"null means unpriced or not rateable. It never means zero."},"ErrorEnvelope":{"type":"object","required":["status","error"],"properties":{"status":{"const":"error"},"error":{"type":"object","required":["code","message"],"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string"},"details":{"type":"object","additionalProperties":{"type":"string"},"description":"Structured, non-sensitive context only. Never a token, a\ndatabase credential, an object key, a log payload or another\norganization's data.\n"}}}}},"ErrorCode":{"type":"string","enum":["BAD_REQUEST","COMMERCE_OWNER_CONFLICT","EVIDENCE_UNAVAILABLE","FORBIDDEN","HOLD_ACTIVE","IDEMPOTENCY_CONFLICT","IMMUTABLE","INTERNAL_ERROR","NOT_FOUND","ORGANIZATION_UID_MISMATCH","PROVIDER_HANDOFF_REQUIRED","REVISION_CONFLICT","UNAUTHENTICATED","UNSUPPORTED","VALIDATION_FAILED"]},"Mode":{"type":"string","enum":["quota_only","fixed","payg"]},"CommerceOwner":{"type":"string","enum":["platform","partner"]},"CollectionMode":{"type":"string","enum":["shadow","billable"]},"AccountState":{"type":"string","enum":["active","growth_blocked","suspended","retained","closed"]},"TransitionState":{"type":"string","enum":["Requested","Validating","Preparing","Scheduled","Active","Blocked","Failed","Cancelled"]},"Quality":{"type":"string","enum":["observed","estimated","missing","unsupported"]},"PricingStatus":{"type":"string","enum":["priced","included","unpriced","unknown_product","not_configured"]},"CoverageState":{"type":"string","enum":["complete","partial","missing","unsupported"]},"Qualification":{"type":"string","enum":["draft","estimate_only","billable","retired"]},"HoldIssuer":{"type":"string","enum":["operator","provider","security","partner"]},"SafetyLimits":{"type":"object","description":"PAYG keeps every ceiling. An absent field is not managed by this\npolicy: the manager neither writes nor removes that surface, and the\norganization's annotation-driven plan no longer drives it once a policy\nexists. An explicit 0 is denial. Those are different, which is why\ncounts are nullable rather than defaulted.\n\nA policy must set at least one ceiling in EVERY mode (defaultsPolicy\nalone is not a ceiling); an empty set is 422. To keep an organization\non its existing plan, do not create a policy for it.\n\nA CPU or memory ceiling (requestsCpu, requestsMemory, limitsCpu,\nlimitsMemory) requires defaultsPolicy, or it is 422: the ceiling puts a\nResourceQuota on every project namespace, and without LimitRange\ndefaults that quota refuses every pod that omits its requests.\n\nLimits are exactly what is stated. No limit is derived from a request\n(a plan's burst ratio does not apply to a policy): a request ceiling\nwith no matching limit leaves that limit unmanaged, and an explicit\nlimit, including 0, is used as given. The same holds for object\nstorage: objectStorageBytes and objectStorageBuckets are managed\nindependently, an absent one is left as it is, and\nobjectStorageBuckets 0 denies new buckets.\n\nQuantity strings are Kubernetes quantities and are PARSED, not merely\nstored: \"8 cores\" or \"-4\" is 422, not accepted desired state that no\nenforcement surface could ever satisfy.\n\nCounts are the one frozen exception to decimals-as-strings (ADR-002 C1).\nThey are bounded at 2^31-1 so the value is exactly representable in\nevery consumer, JavaScript included.\n","properties":{"requestsCpu":{"type":"string"},"requestsMemory":{"type":"string"},"requestsStorage":{"type":"string"},"limitsCpu":{"type":"string"},"limitsMemory":{"type":"string"},"pods":{"type":"integer","minimum":0,"maximum":2147483647},"loadBalancers":{"type":"integer","minimum":0,"maximum":2147483647},"publicIpv4":{"type":"integer","minimum":0,"maximum":2147483647},"projects":{"type":"integer","minimum":0,"maximum":2147483647},"objectStorageBytes":{"type":"string"},"objectStorageBuckets":{"type":"integer","minimum":0,"maximum":2147483647},"accelerators":{"type":"object","additionalProperties":{"type":"object","properties":{"devices":{"type":"integer","minimum":0,"maximum":2147483647},"shares":{"type":"integer","minimum":0,"maximum":2147483647},"memoryMiB":{"type":"integer","minimum":0,"maximum":2147483647},"corePercent":{"type":"integer","minimum":0,"maximum":2147483647}}}},"storageClasses":{"type":"object","description":"Keyed by StorageClass UID, never by class name. A recreated class is\na different product and must not inherit a purchased tier.\n","propertyNames":{"pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"},"additionalProperties":{"type":"string"}},"serviceInstances":{"type":"object","additionalProperties":{"type":"integer","minimum":0}},"defaultsPolicy":{"type":"string","description":"Names the LimitRange default/burst policy, so a PAYG organization\ngets defaults without purchasing a fictitious plan. Without it an\nunspecified request becomes unmetered capacity.\n"}}},"PolicySpec":{"type":"object","required":["contractVersion","organizationRef","account","mode","commerceOwner","collectionMode","limitsRevision","limits","requestedEffectiveAt","revision"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"organizationRef":{"type":"object","required":["name","uid"],"description":"Bound by name AND UID; both immutable after creation.","properties":{"name":{"type":"string","pattern":"^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$"},"uid":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"}}},"account":{"type":"object","required":["accountId"],"properties":{"accountId":{"type":"string"},"partnerId":{"type":"string","description":"Required for a partner-owned account, forbidden for a platform one."},"externalCustomerRef":{"type":"string"}}},"mode":{"$ref":"#/components/schemas/Mode"},"commerceOwner":{"$ref":"#/components/schemas/CommerceOwner"},"collectionMode":{"$ref":"#/components/schemas/CollectionMode"},"rateCardRevision":{"type":"string","pattern":"^[a-z0-9][a-z0-9._-]{0,63}@[a-zA-Z0-9][a-zA-Z0-9._-]{0,63}$","description":"Required for payg, forbidden for quota_only."},"limitsRevision":{"type":"string"},"limits":{"$ref":"#/components/schemas/SafetyLimits"},"requestedEffectiveAt":{"type":"string","format":"date-time","description":"Whole-minute UTC. Activation is no earlier than both this time and\nverified readiness. Never backdated.\n"},"revision":{"type":"string","pattern":"^[1-9][0-9]{0,18}$","description":"Monotonic per-organization integer as a string. Never reused: a\nsecond policy body cannot claim a number an earlier one used.\n"}}},"SurfaceStatus":{"type":"object","required":["applied"],"properties":{"applied":{"type":"boolean"},"reason":{"type":"string"}}},"EnforcementStatus":{"type":"object","description":"Written only by the kube-dc manager. `applied` is a claim about every\nsurface; a backend PATCH returning 200 is not applied entitlement.\n","required":["observedPolicyRevision","applied","updatedAt"],"properties":{"observedPolicyRevision":{"type":"string"},"observedLimitsRevision":{"type":"string"},"applied":{"type":"boolean"},"surfaces":{"type":"object","propertyNames":{"enum":["hrq","limitrange","publicIpv4","objectStorage","accelerators","projects","storageClasses","serviceInstances"]},"additionalProperties":{"$ref":"#/components/schemas/SurfaceStatus"}},"updatedAt":{"type":"string","format":"date-time"}}},"TransitionStatus":{"type":"object","description":"Written only by the billing service.","required":["id","state","requestedRevision","idempotencyKey","updatedAt"],"properties":{"id":{"type":"string"},"state":{"$ref":"#/components/schemas/TransitionState"},"requestedRevision":{"type":"string"},"idempotencyKey":{"type":"string"},"effectiveAt":{"type":["string","null"],"format":"date-time","description":"Set only once Active. May be later than requested, never earlier."},"reason":{"type":"string"},"retryable":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time","description":"Informational. Never use it to order changes; use ordinal and version."},"ordinal":{"type":"string","pattern":"^[1-9][0-9]{0,18}$","description":"Orders an organization's transitions: a later transition always has\na larger ordinal. Integer as a string (ADR-002).\n"},"version":{"type":"string","pattern":"^[1-9][0-9]{0,18}$","description":"Orders the changes of this one transition; it increases on every\nchange of state, reason, retryability or effective time. A client\npolling a transition can compare versions instead of timestamps.\n"}}},"PolicyHistory":{"type":"object","required":["latestRevision","highestRequestedRevision","transitions","intervals"],"properties":{"latestRevision":{"type":"string","pattern":"^(0|[1-9][0-9]{0,18})$","description":"The latest ACTIVATED revision (\"0\" for none) -- a change's expectedRevision. Over the whole record."},"highestRequestedRevision":{"type":"string","pattern":"^(0|[1-9][0-9]{0,18})$","description":"The highest revision any transition ever requested; a new request must exceed it. Over the whole record."},"transitions":{"type":"array","description":"Every requested transition, newest first (by ordinal).","items":{"$ref":"#/components/schemas/PolicyHistoryEntry"}},"intervals":{"type":"array","description":"Every span a revision was in force, newest first.","items":{"$ref":"#/components/schemas/PolicyInterval"}}}},"PolicyHistoryEntry":{"type":"object","required":["transition","spec","requestedBy","requestedAt"],"properties":{"transition":{"$ref":"#/components/schemas/TransitionStatus"},"spec":{"allOf":[{"$ref":"#/components/schemas/PolicySpec"}],"description":"The complete spec this transition asked for."},"requestedBy":{"type":"string","description":"The recorded actor -- subject, display name and vouching service."},"requestedAt":{"type":"string","format":"date-time"},"previousRevision":{"type":"string","description":"The revision in force when this was requested; absent for the first."}}},"PolicyInterval":{"type":"object","description":"A half-open span [effectiveFrom, effectiveTo) during which a revision was in force.","required":["revision","effectiveFrom","effectiveTo","mode","commerceOwner","collectionMode","limitsRevision"],"properties":{"revision":{"type":"string"},"effectiveFrom":{"type":"string","format":"date-time"},"effectiveTo":{"type":["string","null"],"format":"date-time","description":"Null for the revision in force."},"mode":{"$ref":"#/components/schemas/Mode"},"commerceOwner":{"$ref":"#/components/schemas/CommerceOwner"},"collectionMode":{"$ref":"#/components/schemas/CollectionMode"},"rateCardRevision":{"type":"string"},"limitsRevision":{"type":"string"}}},"Hold":{"type":"object","required":["id","issuer","reason","generation","effect","recoveryCriteria","createdAt"],"description":"Owned by its issuer. Clearing a provider payment hold cannot clear an\noperator or security hold, and a mode switch clears none of them.\n","properties":{"id":{"type":"string"},"issuer":{"$ref":"#/components/schemas/HoldIssuer"},"reason":{"type":"string"},"generation":{"type":"string"},"effect":{"$ref":"#/components/schemas/AccountState"},"recoveryCriteria":{"type":"string","description":"What must become true before the issuer may clear it. An\nunverifiable payment state is not one of them.\n"},"createdAt":{"type":"string","format":"date-time"},"clearedAt":{"type":["string","null"],"format":"date-time"}}},"AccountHolds":{"type":"object","required":["organization","organizationUid","state","recognised","holds"],"properties":{"organization":{"type":"string"},"organizationUid":{"type":"string"},"state":{"allOf":[{"$ref":"#/components/schemas/AccountState"}],"description":"The strongest effect still standing; `active` with no holds."},"recognised":{"type":"boolean","description":"False when a hold's effect is unknown to this version."},"holds":{"type":"array","items":{"$ref":"#/components/schemas/Hold"}},"cluster":{"$ref":"#/components/schemas/HoldClusterCoverage"}}},"HoldClusterCoverage":{"type":"object","required":["projected"],"description":"Whether the holds reach the Kubernetes path. They are projected onto the\norganization's billing policy, where the manager caps its quota; an\norganization without a policy is held on the console and API only, and\n`detail` says so. Reported, never assumed.\n","properties":{"projected":{"type":"boolean"},"detail":{"type":"string"}}},"ManagedQuoteRequest":{"type":"object","additionalProperties":false,"required":["plan"],"description":"Names only. Empty fields take the plan's defaults; a sharded plan is\nsized by `shards` x `replicasPerShard`, OpenSearch by `dataReplicas`,\nand member-counted plans by `members`. These shapes cannot be mixed.\n","properties":{"operation":{"enum":["create","resize"]},"plan":{"type":"string","maxLength":253},"cpu":{"type":"string","description":"Kubernetes quantity per data member."},"memory":{"type":"string","description":"Kubernetes quantity per data member."},"storage":{"type":"string","description":"Kubernetes quantity per data member."},"storageClass":{"type":"string","maxLength":253},"members":{"type":"integer","minimum":1,"maximum":1024},"shards":{"type":"integer","minimum":1,"maximum":64},"replicasPerShard":{"type":"integer","minimum":1,"maximum":16},"dataReplicas":{"type":"integer","minimum":1,"maximum":64}}},"ManagedQuote":{"type":"object","required":["quotable","request"],"properties":{"quotable":{"type":"boolean"},"reason":{"enum":["not_payg","plan_not_found","plan_not_commercial","shape_invalid","storage_class","price_unavailable"],"description":"Set when `quotable` is false."},"message":{"type":"string"},"quoteId":{"type":"string","pattern":"^q-[0-9a-f]{32}$"},"createdAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"basis":{"const":"730h"},"pricesEffectiveFrom":{"type":"string","format":"date-time"},"collectionMode":{"$ref":"#/components/schemas/CollectionMode"},"policyRevision":{"type":"string"},"request":{"$ref":"#/components/schemas/ManagedQuoteRequest"},"result":{"$ref":"#/components/schemas/ManagedQuoteResult"},"omitted":{"type":"array","description":"Costs the quote does not include, each with why. Never a zero line.","items":{"type":"object","required":["component","note"],"properties":{"component":{"type":"string"},"note":{"type":"string"}}}}}},"ManagedQuoteResult":{"type":"object","description":"A price preview, never an order authorization or invoice. The plan's\nfee appears once; CPU, memory and storage scale with `members`.\n","required":["rateCard","planUid","planRevision","currency","scope","from","to","members","storageClassUid","storageQualificationRevision","lines","subtotal"],"properties":{"rateCard":{"type":"string"},"planUid":{"type":"string"},"planRevision":{"type":"string"},"currency":{"type":"string"},"scope":{"type":"string"},"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"members":{"type":"integer"},"storageClassUid":{"type":"string"},"storageQualificationRevision":{"type":"integer"},"lines":{"type":"array","items":{"type":"object","required":["sku","unitPrice","priceUnit","baseQuantity","amount"],"properties":{"sku":{"type":"string"},"unitPrice":{"$ref":"#/components/schemas/Decimal"},"priceUnit":{"type":"string"},"baseQuantity":{"$ref":"#/components/schemas/Decimal"},"amount":{"$ref":"#/components/schemas/Decimal"}}}},"subtotal":{"$ref":"#/components/schemas/Decimal"}}},"PolicyStatus":{"type":"object","required":["contractVersion","transition","enforcement","accountState"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"transition":{"$ref":"#/components/schemas/TransitionStatus"},"enforcement":{"$ref":"#/components/schemas/EnforcementStatus"},"accountState":{"allOf":[{"$ref":"#/components/schemas/AccountState"}],"description":"Derived from the active holds, never set directly."},"holds":{"type":"array","items":{"$ref":"#/components/schemas/Hold"}},"providerHandoff":{"type":"object","description":"An unfinished migration away from a previous subscription. Clearing\nplan-id is not a handoff; the previous binding is preserved.\n","properties":{"required":{"type":"boolean"},"completed":{"type":"boolean"},"previousProvider":{"type":"string"},"previousSubscriptionId":{"type":"string"},"previousPlanId":{"type":"string"},"completedAt":{"type":["string","null"],"format":"date-time"}}}}},"PolicyDocument":{"type":"object","required":["spec","status"],"properties":{"spec":{"$ref":"#/components/schemas/PolicySpec"},"status":{"$ref":"#/components/schemas/PolicyStatus"}}},"PolicyPreview":{"type":"object","required":["eligible","limitDelta","missingPrices","missingMeters","unqualifiedProducts","conflicts"],"properties":{"eligible":{"type":"boolean"},"limitDelta":{"type":"object","description":"Keyed by SafetyLimits field name (requestsCpu, pods, publicIpv4,\n...). Against the organization's current policy when it has one --\nits stated values, like with like -- and otherwise against what is\nenforced now.\n","additionalProperties":{"type":"object","properties":{"current":{"type":["string","null"]},"currentSource":{"type":"string","enum":["policy","hrq","organization"],"description":"policy: the current policy's stated value. hrq: the\norganization's hierarchical quota, which includes the\nplatform's per-project system overhead on CPU and memory.\norganization: the manager's published quota status.\n"},"proposed":{"type":["string","null"]},"used":{"type":["string","null"]},"reducesBelowCurrentUsage":{"type":"boolean","description":"A reduction below live allocation follows a separate\ncontrolled workflow; it is surfaced here rather than silently\naccepted or silently dropped. It compares the STATED proposal\nwith usage that includes platform system pods, so it errs\ntoward warning.\n"}}}},"estimatedRunRate":{"type":"object","properties":{"amount":{"allOf":[{"$ref":"#/components/schemas/NullableDecimal"}],"description":"Null until time-integrated usage, class placement and source\ncoverage can be evaluated. Quota ceilings are not spend.\n"},"currency":{"type":"string"},"perUnit":{"type":"string","examples":["month"]},"note":{"type":"string","description":"Why no defensible monetary run rate is available."},"forecast":{"type":"object","description":"This month projected at its rate so far under the proposal\n(the budgets' run-rate method). Both figures are null when no\nprojection can be stated; `note` says why.\n","required":["monthToDate","projected","note"],"properties":{"monthToDate":{"allOf":[{"$ref":"#/components/schemas/NullableDecimal"}]},"projected":{"allOf":[{"$ref":"#/components/schemas/NullableDecimal"}]},"lowerBound":{"type":"boolean","description":"The projection prices only part of the usage."},"note":{"type":"string"}}}}},"missingPrices":{"type":"array","items":{"type":"string"},"description":"Component SKUs with no enabled price at the proposed effective\ntime. An installation without a rate catalog names the unresolved\nrevision as `rateCardRevision:<id>` instead.\n"},"missingMeters":{"type":"array","items":{"type":"string"},"description":"Component SKUs without a defined meter and version."},"unqualifiedProducts":{"type":"array","items":{"type":"string"},"description":"Component SKUs that are not qualified for paid use. A meter and an\nestimate price do not prove a product can be charged.\n"},"conflicts":{"type":"array","items":{"type":"object","required":["code","message"],"properties":{"code":{"$ref":"#/components/schemas/ErrorCode"},"message":{"type":"string"}}}}}},"ProductDefinition":{"type":"object","required":["contractVersion","sku","displayName","role","usageCategory","chargeComponent","qualification"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"sku":{"type":"string","pattern":"^[a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9_]*)+$"},"displayName":{"type":"string"},"role":{"type":"string","enum":["component","offer_group_only"]},"meter":{"type":"string"},"meterVersion":{"type":"string"},"baseUnit":{"type":"string"},"usageCategory":{"type":"string"},"chargeComponent":{"type":"string"},"qualification":{"$ref":"#/components/schemas/Qualification"},"qualificationNote":{"type":"string"},"regions":{"type":"array","items":{"type":"string"}},"planes":{"type":"array","items":{"type":"string"}},"includedComponents":{"type":"array","items":{"type":"string"}},"capacityCoverage":{"type":"string","enum":["general_pool","separate_envelope","not_applicable"]},"classScope":{"$ref":"#/components/schemas/ClassScope"}}},"Rate":{"type":"object","required":["sku","unitPrice","priceUnit","baseUnitsPerPriceUnit","effectiveFrom","enabled"],"properties":{"sku":{"type":"string"},"unitPrice":{"$ref":"#/components/schemas/NullableDecimal"},"priceUnit":{"type":"string"},"baseUnitsPerPriceUnit":{"allOf":[{"$ref":"#/components/schemas/Decimal"}],"description":"Cross-checked against the unit registry at publication."},"included":{"type":"boolean"},"includedQuantity":{"$ref":"#/components/schemas/NullableDecimal"},"effectiveFrom":{"type":"string","format":"date-time"},"effectiveTo":{"type":["string","null"],"format":"date-time"},"enabled":{"type":"boolean","description":"An enabled rate with a null unitPrice is rejected. Null means\nunpriced, not free.\n"}}},"RateCardSummary":{"type":"object","required":["cardId","revision","status","currency","billable"],"properties":{"cardId":{"type":"string"},"revision":{"type":"string"},"status":{"type":"string","enum":["draft","published","retired"]},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"billable":{"type":"boolean"},"publishedAt":{"type":["string","null"],"format":"date-time"},"note":{"type":"string"}}},"RateCardRevision":{"allOf":[{"$ref":"#/components/schemas/RateCardSummary"},{"type":"object","required":["contractVersion","products","rates","createdAt"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"taxIncluded":{"type":"boolean"},"products":{"type":"array","items":{"$ref":"#/components/schemas/ProductDefinition"}},"rates":{"type":"array","items":{"$ref":"#/components/schemas/Rate"}},"storageQualifications":{"type":"array","items":{"$ref":"#/components/schemas/StorageClassQualification"},"description":"The storage classes sold as products of this revision, by UID.\n"},"computeQualifications":{"type":"array","items":{"$ref":"#/components/schemas/ComputeClassQualification"},"description":"The compute classes sold as products of this revision, each\nnaming the machines it consists of.\n"},"createdAt":{"type":"string","format":"date-time"},"retiredAt":{"type":["string","null"],"format":"date-time"}}}]},"ClassScope":{"type":"string","enum":["all","qualified"],"description":"Which classes of its meter family a product covers. \"all\" states that\nit prices every storage or compute class; \"qualified\" that it prices\nexactly the storage classes qualified to it in this revision; absent\nmeans not stated. A product in a family that distinguishes classes\n(CPU, memory, PVC bytes) is only rated with one of the two.\n"},"ComputeClassQualification":{"type":"object","description":"What a compute class IS, as a statement somebody made: the machines in\nit by Node UID -- a machine rebuilt under its name is a different\nmachine, and usage is priced as this class only when the host it was\nmeasured on is one of them -- where those machines are, what they are\nclaimed to be, and, for a class sold as dedicated, how that dedication\nis enforced and what keeps other workloads off. A dedicated class may\nbe offered and estimated; it cannot back a billable product until the\nplatform records who held a machine over an interval (ADR-008).\n","required":["contractVersion","sku","class","installation","cluster","nodes","evidence","qualifiedBy","qualifiedAt","revision"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"sku":{"type":"string","pattern":"^[a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9_]*)+$"},"class":{"type":"string","pattern":"^[a-z0-9]([-a-z0-9_.]*[a-z0-9])?$"},"installation":{"type":"string"},"cluster":{"type":"string"},"nodes":{"type":"array","minItems":1,"items":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"}},"cpuModel":{"type":"string"},"architecture":{"type":"string"},"dedicated":{"type":"boolean"},"isolation":{"type":"string","description":"How dedication is enforced on these machines. A node selector is\nnot isolation. Required when dedicated.\n"},"placement":{"type":"string","description":"What keeps other workloads off these machines. Required when\ndedicated.\n"},"evidence":{"type":"string"},"qualifiedBy":{"type":"string"},"qualifiedAt":{"type":"string","format":"date-time"},"revision":{"type":"integer","minimum":1}}},"StorageClassQualification":{"type":"object","description":"What a storage class IS, as a statement somebody made: the class by\nUID -- a class recreated under the same name has a new UID and is not\nthe purchased product until it is qualified again -- where that UID\nexists, the class as it was observed, what the operator states about\nthe hardware behind it, and the evidence, author and date those claims\nrest on. The mapping revision travels with every charge made under it.\n","required":["contractVersion","sku","classUid","className","provisioner","backend","installation","cluster","role","tier","medium","durability","failureDomain","evidence","qualifiedBy","qualifiedAt","revision"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"sku":{"type":"string","pattern":"^[a-z][a-z0-9]*(\\.[a-z0-9][a-z0-9_]*)+$"},"classUid":{"type":"string","pattern":"^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$"},"className":{"type":"string"},"provisioner":{"type":"string"},"parameters":{"type":"object","additionalProperties":{"type":"string"}},"backend":{"type":"string"},"installation":{"type":"string"},"cluster":{"type":"string"},"role":{"type":"string","enum":["primary","backup","archive","ephemeral"]},"tier":{"type":"string"},"medium":{"type":"string","enum":["nvme","ssd","hdd","mixed","unstated"]},"durability":{"type":"string"},"failureDomain":{"type":"string"},"operations":{"type":"array","items":{"type":"string","enum":["expansion","snapshot","clone","raw_block"]}},"evidence":{"type":"string"},"qualifiedBy":{"type":"string"},"qualifiedAt":{"type":"string","format":"date-time"},"revision":{"type":"integer","minimum":1}}},"RateCardListItem":{"description":"One row of the revision list: the summary plus counts. The counts are\nnamed *Count so they cannot be confused with a revision's products and\nrates collections.\n","allOf":[{"$ref":"#/components/schemas/RateCardSummary"},{"type":"object","required":["createdAt","draftVersion","sourceKind","productCount","rateCount","enabledRateCount","nullPriceCount"],"properties":{"createdAt":{"type":"string","format":"date-time"},"retiredAt":{"type":["string","null"],"format":"date-time"},"draftVersion":{"type":"integer","minimum":1},"sourceKind":{"type":"string","enum":["api","import"]},"productCount":{"type":"integer","minimum":0},"rateCount":{"type":"integer","minimum":0},"enabledRateCount":{"type":"integer","minimum":0},"nullPriceCount":{"type":"integer","minimum":0,"description":"Rates with no price that are not marked included -- unpriced, never free."}}}]},"RateCardProposalV0":{"type":"object","description":"The design-time rate card proposal (kube-dc-rate-card-proposal/v0).\nDecoded strictly: an unknown member, a member named twice, or a JSON\nnumber where a decimal string belongs is refused.\n","required":["schema","id","revision","status","currency","billable","unknownProductPolicy","rates"],"additionalProperties":false,"properties":{"schema":{"const":"kube-dc-rate-card-proposal/v0"},"id":{"type":"string"},"revision":{"type":"string"},"status":{"const":"draft"},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"taxIncluded":{"type":"boolean"},"effectiveAt":{"type":["string","null"],"format":"date-time"},"billable":{"const":false,"description":"An import never creates a billable revision."},"unknownProductPolicy":{"const":"unrated"},"rounding":{"type":"string"},"note":{"type":"string"},"meterSpecification":{"type":"string"},"unpriced":{"type":"array","items":{"type":"string"},"uniqueItems":true},"rates":{"type":"array","items":{"type":"object","required":["sku","unitPrice","priceUnit","baseUnitsPerPriceUnit"],"additionalProperties":false,"properties":{"sku":{"type":"string"},"unitPrice":{"$ref":"#/components/schemas/NullableDecimal"},"priceUnit":{"type":"string"},"baseUnitsPerPriceUnit":{"$ref":"#/components/schemas/Decimal"},"candidateMeter":{"type":["string","null"]},"proposedMeter":{"type":["string","null"]},"readiness":{"type":"string"},"role":{"type":"string","enum":["offer_group_only"]},"note":{"type":"string"},"enabled":{"type":"boolean","description":"Accepted and recorded, never honoured -- every imported rate arrives disabled."}}}}}},"RateCardLifecycle":{"type":"object","description":"Metadata around a revision that the revision document does not carry.\nFrozen, with the revision, once it is published.\n","required":["draftVersion","createdBy","updatedAt","sourceKind"],"properties":{"draftVersion":{"type":"integer","minimum":1},"createdBy":{"type":"string"},"updatedAt":{"type":"string","format":"date-time"},"updatedBy":{"type":"string"},"publishedBy":{"type":"string"},"retiredBy":{"type":"string"},"retireReason":{"type":"string"},"sourceKind":{"type":"string","enum":["api","import"]},"sourceDigest":{"type":"string"}}},"CatalogFinding":{"type":"object","required":["code","message"],"properties":{"sku":{"type":"string"},"code":{"type":"string"},"message":{"type":"string"}}},"CatalogReport":{"type":"object","required":["publishable","problems","warnings"],"properties":{"publishable":{"type":"boolean"},"problems":{"type":"array","items":{"$ref":"#/components/schemas/CatalogFinding"}},"warnings":{"type":"array","items":{"$ref":"#/components/schemas/CatalogFinding"}}}},"RateCardImportReport":{"type":"object","required":["schema","sourceIdentity","sourceRows","products","rates","nullPrices","enabledRates","decisions"],"properties":{"schema":{"type":"string"},"sourceIdentity":{"type":"string"},"sourceRows":{"type":"integer","minimum":0},"unpricedListed":{"type":"integer","minimum":0},"products":{"type":"integer","minimum":0},"rates":{"type":"integer","minimum":0},"nullPrices":{"type":"integer","minimum":0},"enabledRates":{"const":0,"description":"An import never enables a rate."},"resolvedMeters":{"type":"integer","minimum":0},"decisions":{"type":"array","items":{"$ref":"#/components/schemas/CatalogFinding"}}}},"RateCardImportRequest":{"type":"object","required":["source"],"additionalProperties":false,"properties":{"cardId":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$","description":"Defaults to the source id."},"revision":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$","description":"Defaults to the source revision."},"effectiveFrom":{"type":"string","format":"date-time","description":"UTC start of every imported rate; required when the source effectiveAt is null."},"source":{"$ref":"#/components/schemas/RateCardProposalV0"}}},"RateCardUsage":{"type":"object","required":["effectivePolicies","openTransitions"],"properties":{"effectivePolicies":{"type":"integer","minimum":0},"openTransitions":{"type":"integer","minimum":0}}},"RateCardEntryEnvelope":{"type":"object","required":["status","data"],"properties":{"status":{"const":"success"},"data":{"type":"object","required":["revision","lifecycle"],"properties":{"revision":{"$ref":"#/components/schemas/RateCardRevision"},"lifecycle":{"$ref":"#/components/schemas/RateCardLifecycle"},"importReport":{"$ref":"#/components/schemas/RateCardImportReport"}}}}},"CostLine":{"type":"object","required":["dimensions","sku","meter","quantity","unit","pricingStatus","quality","policyRevision","calculationVersion"],"properties":{"dimensions":{"type":"object","additionalProperties":{"type":"string"}},"sku":{"type":"string"},"meter":{"type":"string"},"quantity":{"$ref":"#/components/schemas/Decimal"},"unit":{"type":"string"},"normalizedQuantity":{"$ref":"#/components/schemas/NullableDecimal"},"priceUnit":{"type":"string"},"includedQuantity":{"allOf":[{"$ref":"#/components/schemas/NullableDecimal"}],"description":"The allowance this line consumed, exact and in the line's BASE unit\n(the unit of `quantity`), never rounded and never more than\n`quantity`. `chargedQuantity` and `amount` are\n`(quantity - includedQuantity) / baseUnitsPerPriceUnit`, rounded\nonce at `scale` (ADR-002 C12).\n"},"chargedQuantity":{"$ref":"#/components/schemas/NullableDecimal"},"unitPrice":{"$ref":"#/components/schemas/NullableDecimal"},"amount":{"allOf":[{"$ref":"#/components/schemas/NullableDecimal"}],"description":"Non-null only when pricingStatus is `priced`."},"currency":{"type":"string"},"pricingStatus":{"$ref":"#/components/schemas/PricingStatus"},"quality":{"$ref":"#/components/schemas/Quality"},"chargeComponent":{"type":"string"},"usageCategory":{"type":"string"},"policyRevision":{"type":"string"},"rateRevision":{"type":"string"},"calculationVersion":{"type":"string"},"scale":{"type":"integer","minimum":0,"maximum":30,"description":"Decimal places normalizedQuantity, chargedQuantity and amount are each\nrounded to, once, half up, from exact values; absent or 0 means exact.\nDividing by a denominator such as 3600 rarely terminates, so estimates\ndeclare a scale; the rounding is part of the line and reproducible:\namount = round(unitPrice x (quantity - includedQuantity) /\nbaseUnitsPerPriceUnit) -- from the exact charged quantity, never from\nthe rounded chargedQuantity (ADR-002 C12).\n"},"eventCount":{"type":"integer"},"distinctResources":{"type":"integer"}}},"CoverageEntry":{"type":"object","required":["state","expectedIntervals","observedIntervals","qualification","pricingStatus"],"properties":{"sku":{"type":"string"},"meter":{"type":"string"},"source":{"type":"string"},"state":{"$ref":"#/components/schemas/CoverageState"},"expectedIntervals":{"type":"integer"},"observedIntervals":{"type":"integer"},"watermark":{"type":["string","null"],"format":"date-time"},"gaps":{"type":"array","maxItems":50,"description":"Missing runs of windows, merged by reason, at most 50; moreGaps says the list was cut.","items":{"$ref":"#/components/schemas/CoverageGap"}},"moreGaps":{"type":"boolean"},"qualification":{"$ref":"#/components/schemas/Qualification"},"pricingStatus":{"$ref":"#/components/schemas/PricingStatus"},"note":{"type":"string"}}},"CostReport":{"type":"object","required":["contractVersion","organization","organizationUid","from","to","groupBy","collectionMode","billable","lines","coverage","pricedSubtotal","estimatedTotal","hasMore"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"organization":{"type":"string"},"organizationUid":{"type":"string"},"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"groupBy":{"type":"array","items":{"type":"string"}},"currency":{"type":"string"},"mode":{"allOf":[{"$ref":"#/components/schemas/Mode"}],"description":"The mode of the policy in force at the end of the range; absent when\nnone is (an organization without a policy keeps its existing\nbehaviour, which no mode value describes). `collectionMode` is then\n`shadow`: shadow usage is all there is.\n"},"collectionMode":{"$ref":"#/components/schemas/CollectionMode"},"billable":{"type":"boolean"},"usageSource":{"$ref":"#/components/schemas/UsageSource"},"lines":{"type":"array","items":{"$ref":"#/components/schemas/CostLine"}},"coverage":{"type":"array","items":{"$ref":"#/components/schemas/CoverageEntry"}},"pricedSubtotal":{"$ref":"#/components/schemas/NullableDecimal"},"estimatedTotal":{"allOf":[{"$ref":"#/components/schemas/NullableDecimal"}],"description":"Null whenever any expected component is missing or unpriced. A total\nthat ignores an unknown component is wrong, not approximate.\n"},"nextCursor":{"type":"string"},"hasMore":{"type":"boolean"},"coverageNote":{"type":"string"}}},"ProducerGap":{"type":"object","required":["contractVersion","producerId","windowStart","windowEnd","meters","reason","detectedAt"],"properties":{"contractVersion":{"type":"string"},"producerId":{"type":"string"},"epoch":{"type":"string"},"windowStart":{"type":"string","format":"date-time"},"windowEnd":{"type":"string","format":"date-time"},"meters":{"type":"array","minItems":1,"items":{"type":"string"}},"reason":{"type":"string"},"detectedAt":{"type":"string","format":"date-time"},"organizationUid":{"type":"string","description":"The one organization whose measurement is missing; absent for the whole producer."}}},"CoverageGap":{"type":"object","required":["contractVersion","producerId","windowStart","windowEnd","meters","reason","detectedAt"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"producerId":{"type":"string"},"epoch":{"type":"string","description":"The producer epoch; empty for the in-cluster shadow collector, which has none."},"fromSequence":{"type":"string"},"toSequence":{"type":"string"},"windowStart":{"type":"string","format":"date-time"},"windowEnd":{"type":"string","format":"date-time"},"meters":{"type":"array","minItems":1,"items":{"type":"string"}},"reason":{"type":"string","description":"Why expected component-intervals have no observation. Producer gaps:\nproducer_restart, source_unavailable, sequence_hole, spool_overflow,\nrevoked_identity. Shadow collector: not_collected (no snapshot at\nthe window's start or end), collector_unavailable (the collector\nhas produced nothing since; an open gap), source_unavailable,\ncounter_reset, invalid_value, namespace_changed,\nresource_report_unavailable, dimensions_changed, not_assessed\n(before coverage recording and not yet backfilled).\n"},"detectedAt":{"type":"string","format":"date-time"},"repairedAt":{"type":["string","null"],"format":"date-time"}}},"CoverageReport":{"type":"object","required":["contractVersion","organization","organizationUid","from","to","entries","sources"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"organization":{"type":"string"},"organizationUid":{"type":"string"},"from":{"type":"string","format":"date-time"},"to":{"type":"string","format":"date-time"},"entries":{"type":"array","items":{"$ref":"#/components/schemas/CoverageEntry"}},"sources":{"type":"array","items":{"type":"object","required":["source","state","openGaps"],"properties":{"source":{"type":"string"},"lastAcceptedSequence":{"type":"string"},"lastEventTime":{"type":["string","null"],"format":"date-time"},"lagSeconds":{"type":["integer","null"]},"openGaps":{"type":"integer"},"oldestUnackedBatch":{"type":["string","null"],"format":"date-time"},"state":{"$ref":"#/components/schemas/CoverageState"}}}}}},"SpendBasis":{"type":"string","enum":["total","priced_subtotal","none"],"description":"What a spend figure is. `priced_subtotal` is a lower bound: part of the\nmonth is not measured or not priced, and spending was AT LEAST it.\n"},"ForecastMethod":{"type":"string","enum":["run-rate-v1"]},"ForecastConfidence":{"type":"string","enum":["low","medium","high"]},"Budget":{"type":"object","additionalProperties":false,"required":["contractVersion","amount","currency","thresholds","version"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"amount":{"allOf":[{"$ref":"#/components/schemas/Decimal"}],"description":"Per UTC calendar month; positive."},"currency":{"type":"string","pattern":"^[A-Z]{3}$"},"thresholds":{"type":"array","minItems":1,"maxItems":10,"uniqueItems":true,"items":{"type":"integer","minimum":1,"maximum":1000},"description":"Percentages of `amount`, strictly ascending, e.g. [50, 80, 100]."},"version":{"type":"integer","minimum":0,"description":"The version read; 0 to create."},"updatedAt":{"type":"string","format":"date-time","readOnly":true},"updatedBy":{"type":"string","readOnly":true}}},"BudgetAlert":{"type":"object","required":["period","threshold","spend","currency","lowerBound","budgetAmount","budgetVersion","raisedAt"],"properties":{"period":{"type":"string","format":"date-time"},"threshold":{"type":"integer"},"spend":{"$ref":"#/components/schemas/Decimal"},"currency":{"type":"string"},"lowerBound":{"type":"boolean","description":"The figure was only the priced part of the month; spending was at least it."},"budgetAmount":{"$ref":"#/components/schemas/Decimal"},"budgetVersion":{"type":"integer"},"raisedAt":{"type":"string","format":"date-time"},"notifiedAt":{"type":"string","format":"date-time"}}},"UsageSource":{"type":"string","enum":["metering.resource_usage_events+metering.usage_events","billing.usage_records","billing.usage_records+unbilled"],"description":"The source of the cost report and the budget or forecast derived from\nit. Only the immutable journal's billable facts (`billing.usage_records`)\ncan support a payable report. Shadow aggregates and all attributed\njournal facts read as estimates (`billing.usage_records+unbilled`)\nnever settle. The field is optional for older response producers.\n"},"BudgetStatus":{"type":"object","required":["contractVersion","organization","organizationUid","period","asOf","budget","spend","spendBasis","usedPercent","remaining","alerts"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"organization":{"type":"string"},"organizationUid":{"type":"string"},"period":{"type":"string","format":"date-time"},"asOf":{"type":"string","format":"date-time"},"budget":{"oneOf":[{"$ref":"#/components/schemas/Budget"},{"type":"null"}]},"spend":{"$ref":"#/components/schemas/NullableDecimal"},"spendBasis":{"$ref":"#/components/schemas/SpendBasis"},"usageSource":{"$ref":"#/components/schemas/UsageSource"},"currency":{"type":"string"},"usedPercent":{"allOf":[{"$ref":"#/components/schemas/NullableDecimal"}],"description":"A lower bound when `spendBasis` is `priced_subtotal`."},"remaining":{"allOf":[{"$ref":"#/components/schemas/NullableDecimal"}],"description":"Only when `spendBasis` is `total`; negative when over budget."},"alerts":{"type":"array","items":{"$ref":"#/components/schemas/BudgetAlert"}},"note":{"type":"string"}}},"ForecastReport":{"type":"object","required":["contractVersion","organization","organizationUid","period","asOf","available","method","basis","lowerBound","monthToDate","projected","assumptions","reasons","coverage"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"organization":{"type":"string"},"organizationUid":{"type":"string"},"period":{"type":"string","format":"date-time"},"asOf":{"type":"string","format":"date-time"},"available":{"type":"boolean"},"method":{"$ref":"#/components/schemas/ForecastMethod"},"basis":{"$ref":"#/components/schemas/SpendBasis"},"usageSource":{"$ref":"#/components/schemas/UsageSource"},"lowerBound":{"type":"boolean"},"monthToDate":{"$ref":"#/components/schemas/NullableDecimal"},"projected":{"$ref":"#/components/schemas/NullableDecimal"},"currency":{"type":"string"},"confidence":{"$ref":"#/components/schemas/ForecastConfidence"},"assumptions":{"type":"array","items":{"type":"string"}},"reasons":{"type":"array","items":{"type":"string"}},"coverage":{"type":"array","items":{"$ref":"#/components/schemas/CoverageEntry"}}}},"ProducerScope":{"type":"object","additionalProperties":false,"required":["installationUid","meters"],"properties":{"installationUid":{"type":"string"},"dataPlaneUid":{"type":"string","description":"Required for a remote producer; empty only for the in-cluster collector."},"clusterUid":{"type":"string"},"meters":{"type":"array","minItems":1,"items":{"type":"string"},"description":"The meters this producer may report. A batch naming any other is refused."}}},"ProducerRegistration":{"type":"object","required":["contractVersion","producerId","scope","epoch","registeredAt"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"producerId":{"type":"string"},"scope":{"$ref":"#/components/schemas/ProducerScope"},"epoch":{"type":"string","pattern":"^[1-9][0-9]*$","description":"Sequences are comparable only within one epoch."},"registeredAt":{"type":"string","format":"date-time"},"revokedAt":{"type":["string","null"],"format":"date-time"}}},"UsageBatch":{"type":"object","additionalProperties":false,"required":["contractVersion","producerId","epoch","sequence","windowStart","windowEnd","events","idempotencyKey"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"producerId":{"type":"string"},"epoch":{"type":"string","pattern":"^[1-9][0-9]*$"},"sequence":{"type":"string","pattern":"^[1-9][0-9]*$","description":"Monotonic within the epoch; a hole is a visible, repairable gap."},"windowStart":{"type":"string","format":"date-time"},"windowEnd":{"type":"string","format":"date-time"},"idempotencyKey":{"type":"string","minLength":1,"description":"A retry carries the same key AND the same content; the same key with different content is 409."},"events":{"type":"array","minItems":1,"maxItems":5000,"items":{"type":"object"},"description":"CloudEvents 1.0 usage events. Every event's window falls inside the\nbatch window, ids are unique within the batch, and quantities are\nexact decimal strings.\n"}}},"BatchAck":{"type":"object","required":["contractVersion","producerId","epoch","acceptedSequence","accepted","duplicate","nextExpectedSequence","committedAt"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"producerId":{"type":"string"},"epoch":{"type":"string"},"acceptedSequence":{"type":"string","pattern":"^[1-9][0-9]*$","description":"The highest CONTIGUOUS sequence the journal holds; it never runs past a hole."},"accepted":{"type":"integer","minimum":0},"duplicate":{"type":"integer","minimum":0},"conflicts":{"type":"array","items":{"type":"string"},"description":"Event ids whose stored fact differs from the one offered. Never overwritten."},"nextExpectedSequence":{"type":"string","pattern":"^[1-9][0-9]*$","description":"Strictly after acceptedSequence; where a recovering producer resumes."},"committedAt":{"type":"string","format":"date-time"}}},"ConsoleCredentials":{"type":"object","description":"Treat as a secret.","properties":{"success":{"type":"boolean"},"username":{"type":"string"},"password":{"type":"string"}}},"PrometheusRange":{"type":"object","description":"A Prometheus range query answer (`data.result[].values` are [unix time, value] pairs).","additionalProperties":true,"properties":{"status":{"type":"string"},"data":{"type":"object","properties":{"resultType":{"type":"string"},"result":{"type":"array","items":{"type":"object"}}}}}},"VmMetrics":{"type":"object","properties":{"cpu":{"$ref":"#/components/schemas/PrometheusRange"},"ram":{"$ref":"#/components/schemas/PrometheusRange"},"storage":{"$ref":"#/components/schemas/PrometheusRange"},"diskio":{"$ref":"#/components/schemas/PrometheusRange"}}},"ShellSession":{"type":"object","properties":{"svc_id":{"type":"string","description":"Terminal id to connect to."}}},"ShellStatus":{"type":"object","properties":{"ready":{"type":"boolean"},"message":{"type":"string"},"ip":{"type":"string"},"port":{"type":"integer"}}},"VolumeTreeItem":{"type":"object","properties":{"id":{"type":"integer"},"uid":{"type":"string"},"name":{"type":"string"},"inner_name":{"type":"string"},"storageClass":{"type":"string"},"type":{"type":"string"},"capacity":{"type":"string","example":"20Gi"},"attached":{"type":"string"},"attachedTo":{"type":"string"},"startedTimestamp":{"type":"string","format":"date-time"}}},"VmWithInstance":{"type":"object","description":"A VirtualMachine with its running instance, when there is one.","properties":{"vm":{"$ref":"#/components/schemas/KubernetesResource"},"vmi":{"description":"The running VirtualMachineInstance, or a Kubernetes NotFound Status (code 404) when the VM is not running.","anyOf":[{"$ref":"#/components/schemas/KubernetesStatus"},{"$ref":"#/components/schemas/KubernetesResource"}]}}},"GoldenImage":{"type":"object","description":"A Ready golden image a VM root disk can be cloned from instantly.","properties":{"osFamilyId":{"type":"string"},"osName":{"type":"string"},"snapshotName":{"type":"string"},"storageClass":{"type":"string"},"size":{"type":"string"},"mode":{"type":"string","enum":["Filesystem","Block"],"description":"Block goldens give live-migratable roots."}}},"MigrationPool":{"type":"object","description":"Nodes that share a CPU model, so VMs can live-migrate between them.","properties":{"cpuModel":{"type":"string"},"vendor":{"type":"string"},"count":{"type":"integer"}}},"StorageClassOption":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"isDefault":{"type":"boolean"},"provisioner":{"type":"string"},"capabilities":{"type":"array","description":"Supported access and volume mode pairs.","items":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"string"},"example":["ReadWriteMany","Block"]}},"displayName":{"type":"string","description":"Human name of the class (storage.kube-dc.com/display-name), else the class name."},"tier":{"type":"string","description":"Storage tier (local, local-snap, capacity, balanced, performance, scratch); empty when unclassified."},"kind":{"type":"string","enum":["block","file","object"]},"nodeLocal":{"type":"boolean"},"deprecated":{"type":"boolean"},"features":{"type":"array","description":"Capabilities such as snapshot, clone, expand, rwx-block, live-migration.","items":{"type":"string"}},"modes":{"type":"array","description":"Supported access and volume mode pairs from the storage capability contract.","items":{"type":"array","minItems":2,"maxItems":2,"items":{"type":"string"}}},"snapshotClass":{"type":"string"},"pool":{"type":"string","description":"Storage pool identity (\"<cluster>/<pool>\") when known; restores and clones stay in it."}}},"OsImage":{"type":"object","description":"An operating system image the VM wizard offers. Upper-case fields come from the image catalog.","additionalProperties":true,"properties":{"OS_NAME":{"type":"string"},"CLOUD_USER":{"type":"string"},"OS_IMAGE_URL":{"type":"string"},"MIN_MEMORY":{"type":"string"},"MIN_VCPU":{"type":"string"},"MIN_STORAGE":{"type":"string"},"FIRMWARE_TYPE":{"type":"string"},"GUEST_AGENT":{"type":"boolean"},"SSH_ACCESS":{"type":"boolean"},"_familyId":{"type":"string"},"_latestURL":{"type":"string"},"_versions":{"type":"array","items":{"type":"object","properties":{"displayName":{"type":"string"},"tag":{"type":"string"},"imageURL":{"type":"string"},"isLatest":{"type":"boolean"},"sha256":{"type":"string"},"sizeBytes":{"type":"integer"},"uploadedAt":{"type":"string"}}}}}},"NextProjectCidr":{"type":"object","properties":{"success":{"type":"boolean"},"cidrBlock":{"type":"string","example":"10.0.12.0/24"},"exhausted":{"type":"boolean","description":"True when the pool is full and the legacy fallback was used."}}},"BulkDeleteResult":{"type":"object","description":"Outcome of a bulk delete. Each name is deleted independently.","properties":{"total":{"type":"integer"},"successful":{"type":"integer"},"failed":{"type":"integer"},"results":{"type":"array","items":{"type":"object","description":"One entry per name; the name field is named after the kind (deploymentName, podName, ...).","additionalProperties":true,"properties":{"success":{"type":"boolean","description":"Whether Kubernetes accepted the delete."},"status":{"type":"integer","description":"Kubernetes' HTTP status for this delete."},"response":{"$ref":"#/components/schemas/KubernetesResource"},"error":{"type":"string","description":"Set when the request could not be made."}}}}}},"KubeconfigSetup":{"type":"object","properties":{"script":{"type":"string","description":"Shell commands that install the kube-dc CLI and sign in."},"currentOs":{"type":"string"},"domain":{"type":"string"},"organization":{"type":"string"},"project":{"type":"string"},"osOptions":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string","example":"linux_amd64"},"name":{"type":"string"}}}}}},"SecretSync":{"type":"object","properties":{"enabled":{"type":"boolean"},"targetSecretName":{"type":"string","description":"Kubernetes Secret to write; defaults to the ManagedSecret name."},"refreshInterval":{"type":"string","example":"1h"},"keys":{"type":"array","items":{"type":"string"},"description":"Keys to sync; empty syncs all."}}},"ManagedSecretSummary":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"creationTimestamp":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["opaque","password","api-key","tls","db-static"]},"description":{"type":"string"},"sync":{"$ref":"#/components/schemas/SecretSync"},"rotation":{"type":"object"},"publicationRef":{"type":"object","description":"Present when the secret is published by a managed service. Such secrets are read-only."},"readOnly":{"type":"boolean"},"status":{"type":"object","properties":{"conditions":{"type":"array","items":{"type":"object"}},"syncedSecretName":{"type":"string"}}},"openbao":{"type":"object","description":"KV metadata, present on single-secret reads.","properties":{"currentVersion":{"type":"integer"},"createdTime":{"type":"string","format":"date-time"},"updatedTime":{"type":"string","format":"date-time"},"maxVersions":{"type":"integer"},"casRequired":{"type":"boolean"},"customMetadata":{"type":"object","additionalProperties":{"type":"string"}}}},"value":{"type":"object","description":"The current version. Only with `includeValue=true`.","properties":{"data":{"$ref":"#/components/schemas/SecretValues"},"metadata":{"type":"object","description":"The version's OpenBao metadata (version, created_time, ...).","properties":{"version":{"type":"integer"}}}}},"valueMissing":{"type":"boolean","description":"True when the secret has no values yet."}}},"SecretValues":{"type":"object","additionalProperties":{"type":"string"},"example":{"username":"app","password":"s3cr3t"}},"RegistrationResult":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"email":{"type":"string"},"requiresOrgSetup":{"type":"boolean","description":"The account exists and is verified but has no organization yet."}}},"OrgNameAvailability":{"type":"object","properties":{"success":{"type":"boolean"},"orgName":{"type":"string","description":"The name as it would be stored."},"exists":{"type":"boolean"},"available":{"type":"boolean"},"message":{"type":"string"}}},"OrganizationCreated":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"organization":{"type":"string"},"project":{"type":"string"},"role":{"type":"string","const":"org-admin"},"billingMode":{"type":"string","enum":["payg"]},"redirectUrl":{"type":"string"},"token":{"type":"string","description":"An access token for the new organization realm","for signing straight in.":null},"refreshToken":{"type":"string"},"promoTrialActivated":{"type":"boolean"},"promoTrialDetails":{"type":["object","null"]}}},"SuccessMessage":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}},"PublicBranding":{"type":"object","properties":{"productName":{"type":"string"},"productTagline":{"type":"string"},"logoUrl":{"type":["string","null"]},"logoDarkUrl":{"type":["string","null"]},"loginLogoUrl":{"type":["string","null"]},"faviconUrl":{"type":["string","null"]},"colors":{"type":"object","properties":{"primary":{"type":"string","example":"#1f6feb"},"accent":{"type":"string"}}},"colorMode":{"type":"string"},"logoIncludesName":{"type":"boolean"},"disabledSections":{"type":"array","description":"Tenant console sections hidden on this installation (presentation only; access is unchanged).","items":{"type":"string","enum":["kubernetes","managed-services","vms","clusters","databases","networking","object-storage","block-storage","security"]}},"schemaVersion":{"type":"integer","const":1},"resolutionState":{"type":"string","description":"`fallback` when stock defaults are returned."},"rev":{"type":"string","description":"Changes whenever branding changes; asset URLs carry it to bust caches."}}},"OrgUser":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["Active","Inactive"]},"joinedAt":{"type":"string","format":"date-time"}}},"OrgUserResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrgUser"}}}]},"OrgUserDeletedResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"userId":{"type":"string"}}}}}]},"UserGroupsResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"string"},"description":"Group names."},"userId":{"type":"string"},"total":{"type":"integer"}}}]},"UserGroupsChangeResponse":{"type":"object","description":"Returned with 200 when every change succeeded and 207 when some failed.","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"userId":{"type":"string"},"action":{"type":"string","enum":["assign","remove"]},"results":{"type":"array","items":{"type":"object"}},"summary":{"type":"object","properties":{"total":{"type":"integer"},"successful":{"type":"integer"},"failed":{"type":"integer"}}}}}}},"ProjectRole":{"type":"object","properties":{"id":{"type":"string","description":"`<namespace>/<role>`"},"name":{"type":"string"},"namespace":{"type":"string"},"project":{"type":"string"},"scope":{"type":"string","const":"Project"},"description":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"rules":{"type":"array","items":{"type":"object"},"description":"Kubernetes RBAC PolicyRules."},"resourceCount":{"type":"integer"},"verbCount":{"type":"integer"}}},"ProjectRoleListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/ProjectRole"}},"total":{"type":"integer"},"organization":{"type":"string"},"projectId":{"type":"string"}}}]},"ProjectRoleResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ProjectRole"}}}]},"ProjectRoleDeletedResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"deleted":{"type":"boolean","const":true},"roleName":{"type":"string"},"projectId":{"type":"string"}}}}}]},"ProjectQuotaRemovedResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"pooled":{"type":"boolean","const":true,"description":"The project now draws from the organization's shared quota."},"action":{"type":"string","enum":["delete","none"],"description":"`none` when the project had no quota of its own."}}}}}]},"OrganizationGroupDeletedResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationGroup"}}}]},"JoinDecisionResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"userId":{"type":"string"},"email":{"type":"string"},"organization":{"type":"string"},"group":{"type":"string","description":"Approval only."},"emailSent":{"type":"boolean","description":"Whether the person was notified by email."}}}}}]},"VlanAssignResult":{"type":"object","properties":{"success":{"type":"boolean"},"network":{"type":"string","description":"Name of the ProjectNetwork that was created."}}},"VlanReleaseResult":{"type":"object","properties":{"success":{"type":"boolean"},"state":{"type":"string","const":"releasing"}}},"OrgUserListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"total":{"type":"integer"},"source":{"type":"string"},"keycloak":{"type":"object","properties":{"available":{"type":"boolean"},"realm":{"type":"string"},"url":{"type":"string"}}},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"status":{"type":"string"},"joinedAt":{"type":"string","format":"date-time"},"permissions":{"type":"object","properties":{"canManageProjects":{"type":"boolean"},"canManageUsers":{"type":"boolean"},"canViewResources":{"type":"boolean"}}}}}}}}]},"AvailableGroupListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"total":{"type":"integer"},"baseGroupsCount":{"type":"integer"},"orgGroupsCount":{"type":"integer"},"organization":{"type":"string"},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"displayName":{"type":"string"},"description":{"type":"string"},"type":{"type":"string"},"path":{"type":"string"},"projects":{"type":"string"}}}}}}]},"OrgProjectListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"uid":{"type":"string"},"displayName":{"type":"string"},"description":{"type":"string"},"status":{"type":"string","description":"Deleting takes precedence over readiness."},"deletionTimestamp":{"type":"string","format":"date-time","description":"Present while project cleanup runs."},"statusDetails":{"allOf":[{"$ref":"#/components/schemas/ProjectStatus"}],"description":"The Project's status as stored."}}}}}}]},"OrgProjectResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Project"}}}]},"QuotaFigures":{"type":"object","properties":{"hard":{"type":"object","additionalProperties":{"type":"string"}},"used":{"type":"object","additionalProperties":{"type":"string"}}}},"ProjectQuotaResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"projectNamespace":{"type":"string"},"projectQuota":{"anyOf":[{"$ref":"#/components/schemas/QuotaFigures"},{"type":"null"}],"description":"The project's own ResourceQuota; null when none is set."},"hrqQuotas":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/QuotaFigures"},{"type":"object","properties":{"name":{"type":"string"}}}]}},"orgHRQ":{"allOf":[{"$ref":"#/components/schemas/QuotaFigures"},{"type":"object","properties":{"enforcedHard":{"type":"object","additionalProperties":{"type":"string"},"description":"What Kubernetes enforces (the HRQ's spec.hard). On a plan it includes room for one plan-max VM's virtualization overhead, so usage up to it is within quota although above `hard`, which keeps the plan's values."},"annotations":{"type":"object","additionalProperties":{"type":"string"},"description":"The HRQ's annotations, including the plan values as billing.kube-dc.com/entitled-*."},"accelerators":{"type":"object","description":"GPU quota usage by profile","when GPUs are enabled.":null}}}],"description":"The organization-wide quota the project draws from."}}}}}]},"JoinRequestListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"count":{"type":"integer"},"data":{"type":"array","items":{"type":"object"}}}}]},"OrgAuditListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"total":{"type":"integer"},"organization":{"type":"string"},"filters":{"type":"object"},"pagination":{"type":"object","properties":{"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}}},"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"timestamp":{"type":"string","format":"date-time"},"action":{"type":"string"},"resource":{"type":"object","properties":{"kind":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"}}},"user":{"type":"string"},"message":{"type":"string"},"type":{"type":"string"},"count":{"type":"integer"},"source":{"type":"string"},"project":{"type":"string"}}}}}}]},"VlanListResponse":{"type":"object","properties":{"success":{"type":"boolean"},"enabled":{"type":"boolean","description":"Whether tenant VLANs are enabled."},"items":{"type":"array","items":{"type":"object"}}}},"OrgSuccess":{"type":"object","description":"Envelope used by the organization endpoints.","properties":{"success":{"type":"boolean","const":true},"data":{},"timestamp":{"type":"string","format":"date-time"},"message":{"type":"string"}}},"OrgError":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"type":"string"},"status":{"type":"integer"},"message":{"type":"string"},"details":{}}},"OrgSettings":{"type":"object","properties":{"name":{"type":"string"},"description":{"type":"string"},"email":{"type":"string","format":"email","description":"Billing and notification contact."}}},"SessionPolicy":{"type":"object","properties":{"idleSeconds":{"type":"integer","description":"Sign-out after this much inactivity."},"maxSeconds":{"type":"integer","description":"Maximum session length."},"clientIdleSeconds":{"type":"integer"},"clientMaxSeconds":{"type":"integer"},"canManage":{"type":"boolean","description":"Whether the caller may change the policy."}}},"OrganizationGroupView":{"type":"object","description":"An OrganizationGroup as the console shows it.","properties":{"id":{"type":"string"},"name":{"type":"string"},"displayName":{"type":"string"},"description":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"permissions":{"type":"array","items":{"type":"object"}},"labels":{"type":"object","additionalProperties":{"type":"string"}},"annotations":{"type":"object","additionalProperties":{"type":"string"}},"spec":{"$ref":"#/components/schemas/OrganizationGroupSpec"},"status":{"$ref":"#/components/schemas/OrganizationGroupStatus"},"projectCount":{"type":"integer"},"projects":{"type":"array","items":{"type":"string"}},"resourceVersion":{"type":"string"}}},"OrganizationGroupResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrganizationGroupView"}}}]},"OrganizationGroupListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/OrganizationGroupView"}},"total":{"type":"integer"},"organization":{"type":"string"}}}]},"BucketListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"count":{"type":"integer"},"buckets":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"bucketName":{"type":"string"},"storageClass":{"type":"string"},"phase":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"endpoint":{"type":"string"},"port":{"type":"string"},"region":{"type":"string"},"hasCredentials":{"type":"boolean"}}}}}}}}]},"ObjectStorageCredentialsResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"accessKeyId":{"type":"string"},"secretAccessKey":{"type":"string"},"endpoint":{"type":"string"},"organization":{"type":"string"}}}}}]},"ObjectStorageKeyListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"endpoint":{"type":"string"},"organization":{"type":"string"},"keys":{"type":"array","items":{"type":"object","properties":{"accessKey":{"type":"string"},"user":{"type":"string"},"secretKeyHint":{"type":"string","description":"The last characters of the secret key only."}}}}}}}}]},"ObjectStorageQuotaResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"enabled":{"type":"boolean"},"organization":{"type":"string"},"phase":{"type":"string"},"quotas":{"type":"object","properties":{"maxSize":{"type":"string"},"maxBuckets":{"type":"integer"},"maxObjects":{"type":"integer"}}},"usage":{"type":"object","properties":{"bucketCount":{"type":"integer"},"sizeBytes":{"type":"integer"},"objectCount":{"type":"integer"},"usageUnavailable":{"type":"boolean"}}},"userQuota":{"type":"object","description":"The storage backend's own quota record."}}}}}]},"ObjectStorageEndpointResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"endpoint":{"type":"string"},"region":{"type":"string"},"pathStyle":{"type":"boolean"},"protocol":{"type":"string"}}}}}]},"BucketCreatedResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"name":{"type":"string"},"bucketName":{"type":"string","description":"The bucket's name in S3 (generated)."},"phase":{"type":"string"}}}}}]},"BucketDetailResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"name":{"type":"string"},"bucketName":{"type":"string"},"storageClass":{"type":"string"},"phase":{"type":"string"},"createdAt":{"type":"string","format":"date-time"},"s3Endpoint":{"type":"string"},"credentials":{"type":["object","null"],"description":"The bucket's own access key. Treat as a secret.","properties":{"accessKeyId":{"type":"string"},"secretAccessKey":{"type":"string"}}},"config":{"type":["object","null"],"properties":{"host":{"type":"string"},"port":{"type":"string"},"name":{"type":"string"},"region":{"type":"string"}}}}}}}]},"NameResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"name":{"type":"string"}}}}}]},"AccessKeyCreatedResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","description":"The secret is returned only here.","properties":{"accessKey":{"type":"string"},"secretKey":{"type":"string"},"user":{"type":"string"}}}}}]},"BucketPolicyResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"access":{"type":"string","enum":["private","public-read"]},"policy":{"type":["object","null"],"description":"The S3 bucket policy document","if any.":null}}}}}]},"ObjectListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"prefix":{"type":"string"},"isTruncated":{"type":"boolean"},"nextContinuationToken":{"type":["string","null"]},"keyCount":{"type":"integer"},"objects":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Name relative to the prefix."},"key":{"type":"string"},"type":{"type":"string","enum":["folder","file"]},"size":{"type":"integer"},"lastModified":{"type":"string","format":"date-time"},"etag":{"type":"string"}}}}}}}}]},"ObjectKeyResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"key":{"type":"string"},"deleted":{"type":"integer","description":"For a folder","how many objects were deleted.":null},"size":{"type":"integer","description":"For an upload","the file size in bytes.":null}}}}}]},"PresignedUrlResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"key":{"type":"string"},"expiresIn":{"type":"integer","description":"Seconds."}}}}}]},"ObjectMovedResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"sourceKey":{"type":"string"},"destinationKey":{"type":"string"}}}}}]},"ProjectNetworkList":{"type":"object","properties":{"success":{"type":"boolean"},"enabled":{"type":"boolean","description":"Whether tenant VLANs are enabled."},"items":{"type":"array","items":{"type":"object"}}}},"VMAddressNetwork":{"type":"object","required":["name","nadName","provider","cidrBlock","gateway","excludeIps","unavailableRanges","suggestedAddresses","ready","staticIPSupported"],"properties":{"name":{"type":"string"},"nadName":{"type":"string","description":"The assigned interface's NetworkAttachmentDefinition."},"provider":{"type":"string","description":"Managed address provider for this Project interface."},"cidrBlock":{"type":"string"},"gateway":{"type":"string"},"excludeIps":{"type":"array","items":{"type":"string"},"description":"Reserved addresses","ranges":null,"or delegated CIDRs.":null},"unavailableRanges":{"type":"array","items":{"type":"string"},"description":"Allocated addresses and requests from existing VM templates."},"suggestedAddresses":{"type":"array","items":{"type":"string","format":"ipv4"},"description":"Available addresses at the time of this read. Suggestions do not reserve addresses."},"ready":{"type":"boolean"},"staticIPSupported":{"type":"boolean"},"reason":{"type":"string","description":"Why a chosen address is unavailable."}}},"VMAddressNetworkList":{"type":"object","required":["items"],"properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/VMAddressNetwork"}}}},"VmInterface":{"type":"object","properties":{"name":{"type":"string"},"interfaceName":{"type":"string"},"mac":{"type":"string"},"ipAddress":{"type":"string"},"ipAddresses":{"type":"array","items":{"type":"string"}}}},"RoutedNetworkAttachment":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"allocation":{"type":"string"},"direction":{"type":"string","example":"routed-egress"},"ready":{"type":"boolean"},"gateway":{"type":"object","properties":{"replicas":{"type":"integer"},"readyReplicas":{"type":"integer"},"haMode":{"type":"string"}}},"bgp":{"type":"object"},"destinations":{"type":"array","items":{"type":"string"},"description":"Imported prefixes."},"advertised":{"type":"array","items":{"type":"string"}},"routes":{"type":"object","properties":{"accepted":{"type":"integer"},"rejected":{"type":"integer"}}}}},"RoutedNetworkAllocation":{"type":"object","properties":{"name":{"type":"string"},"phase":{"type":"string"},"sharing":{"type":"string","example":"multiple-projects"},"destinations":{"type":"array","items":{"type":"string"}},"attachedProjects":{"type":"array","items":{"type":"string"}},"attachments":{"type":"array","items":{"allOf":[{"$ref":"#/components/schemas/RoutedNetworkAttachment"},{"type":"object","properties":{"project":{"type":"string"}}}]}},"ready":{"type":"boolean"},"message":{"type":"string"}}},"StatusEnvelope":{"type":"object","properties":{"status":{"type":"string","enum":["success","error"]},"error":{"type":"string"}}},"KMSKeySummary":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"creationTimestamp":{"type":"string","format":"date-time"},"purpose":{"type":"string","enum":["application","backup","etcd"]},"algorithm":{"type":"string","enum":["aes256-gcm96","chacha20-poly1305"]},"deletionPolicy":{"type":"string","enum":["retain","schedule"]},"rotation":{"$ref":"#/components/schemas/KmsKeyRotation"},"exportable":{"type":"boolean"},"status":{"type":"object","properties":{"keyId":{"type":"string","description":"OpenBao Transit key, `<org>/transit/keys/<key>`. Empty until the controller provisions it."},"currentVersion":{"type":"integer"},"minDecryptionVersion":{"type":"integer"},"lastRotatedTime":{"type":"string","format":"date-time"},"nextRotationTime":{"type":"string","format":"date-time"},"scheduledDeletion":{"type":"string","format":"date-time"},"conditions":{"type":"array","items":{"type":"object"}}}}}},"KmsKeyRotation":{"type":"object","properties":{"enabled":{"type":"boolean"},"interval":{"type":"string","description":"Rotation period, required when `enabled` is true.","example":"720h"}}},"KmsKeyCreate":{"type":"object","properties":{"purpose":{"type":"string","enum":["application","backup","etcd"],"default":"application"},"algorithm":{"type":"string","enum":["aes256-gcm96","chacha20-poly1305"],"default":"aes256-gcm96"},"deletionPolicy":{"type":"string","enum":["retain","schedule"],"default":"retain"},"rotation":{"$ref":"#/components/schemas/KmsKeyRotation"},"exportable":{"type":"boolean","description":"Must be false; exportable keys are not supported."}}},"KmsKeyAction":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"keyName":{"type":"string","description":"OpenBao Transit key name."},"reconcileTriggered":{"type":"boolean","description":"Whether the controller was asked to refresh the KMSKey status right away."}}},"ManagedClusterCreate":{"description":"A cluster name with its KdcCluster spec fields at the top level, plus optional metadata.","allOf":[{"$ref":"#/components/schemas/KdcClusterSpec"},{"type":"object","required":["name"],"properties":{"name":{"type":"string","pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$","description":"Required; Kubernetes rejects an unnamed cluster."},"version":{"type":"string","description":"Kubernetes version; the installation's default when omitted."},"labels":{"type":"object","additionalProperties":{"type":"string"}},"annotations":{"type":"object","additionalProperties":{"type":"string"}}}}]},"ClusterCreated":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"message":{"type":"string"}}},"ClusterMessage":{"type":"object","properties":{"message":{"type":"string"}}},"ClusterKubeconfig":{"type":"object","description":"Treat as a secret.","properties":{"kubeconfig":{"type":"string","description":"Kubeconfig YAML."},"secretName":{"type":"string"}}},"ClusterItems":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}}}},"ClusterScaled":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}},"KubeletUpdated":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"kubelet":{"type":["object","null"],"description":"The kubelet settings now applied to new nodes."}}},"ClusterExposure":{"type":"object","properties":{"success":{"type":"boolean"},"enabled":{"type":"boolean"},"changed":{"type":"boolean","description":"False when exposure and any supplied client CIDRs are already in the requested state."}}},"ControlPlaneUsage":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"cpu":{"type":"string"},"memory":{"type":"string"}}}},"totals":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"}}}}},"UpgradeInfo":{"type":"object","properties":{"currentVersion":{"type":"string"},"latestVersion":{"type":"string"},"isLatest":{"type":"boolean"},"upgradeAvailable":{"type":"boolean"},"upgradeVersion":{"type":["string","null"]},"upgradeImage":{"type":["string","null"]},"catalogSource":{"type":"string"},"catalogUnavailable":{"type":"boolean"}}},"UpgradeStarted":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"},"previousVersion":{"type":"string"},"targetVersion":{"type":"string"},"targetImage":{"type":["string","null"]},"workerImagePatches":{"type":"array","items":{"type":"object"}}}},"PoolAutoscaling":{"type":"object","properties":{"pool":{"type":"string"},"replicas":{"type":"integer"},"autoscaling":{"type":["object","null"],"description":"The stored settings (enabled","minReplicas":null,"maxReplicas":null,"behavior).":null},"status":{"type":["object","null"],"description":"What the autoscaler last observed."}}},"PoolAutoscalingUpdated":{"type":"object","properties":{"success":{"type":"boolean"},"pool":{"type":"string"},"applied":{"type":["object","null"],"description":"The settings as read back after the write."},"autoscaling":{"type":"object"},"adjustedReplicas":{"type":"integer","description":"Set when the pool's size was moved into the new range."},"warning":{"type":"string"}}},"DatastoreList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"phase":{"type":"string"},"etcdReady":{"type":"boolean"},"etcdReplicas":{"type":"integer"},"exposure":{"type":"string"},"referenceCount":{"type":"integer","description":"Clusters using this datastore."},"endpoint":{"type":"string"},"port":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}}}}}},"DatastorePorts":{"type":"object","properties":{"usedPorts":{"type":"array","items":{"type":"integer"}},"availablePorts":{"type":"array","items":{"type":"integer"}},"suggestedPort":{"type":"integer"}}},"KubernetesVersionOptions":{"type":"object","properties":{"versions":{"type":"array","items":{"$ref":"#/components/schemas/ValueLabelOption"}}}},"WorkerImageOptions":{"type":"object","properties":{"images":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"architecture":{"type":"string"},"default":{"type":"boolean"},"k8sVersion":{"type":"string"}}}}}},"WorkerPool":{"type":"object","properties":{"name":{"type":"string"},"replicas":{"type":"integer","default":2},"cpuCores":{"type":"integer","default":1},"memory":{"type":"string","description":"Quantity, or a number of GiB.","example":"4Gi"},"infrastructureProvider":{"type":"string","default":"kubevirt"},"storageType":{"type":"string"},"image":{"type":"string"},"diskSize":{"type":"string","description":"Quantity, or a number of GiB.","example":"40Gi"}}},"ManagedClusterList":{"type":"object","properties":{"total":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"},"version":{"type":"string","example":"v1.33.1"},"phase":{"type":"string"},"endpoint":{"type":"string","description":"API server URL, or `Pending`."},"controlPlaneReplicas":{"type":"integer"},"controlPlaneReady":{"type":"boolean"},"dataStoreName":{"type":"string"},"eipName":{"type":"string"},"workerPools":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"replicas":{"type":"integer"},"provider":{"type":"string"},"cpuCores":{"type":"integer"},"memory":{"type":"string"}}}},"labels":{"type":"object","additionalProperties":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"}}}}}},"ManagedCluster":{"type":"object","description":"The cluster's spec and status as stored, with trimmed metadata.","properties":{"metadata":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"},"labels":{"type":"object","additionalProperties":{"type":"string"}},"annotations":{"type":"object","additionalProperties":{"type":"string"},"description":"`kube-dc.com/restore-from` and `kube-dc.com/restore-state` track a restore in progress."},"creationTimestamp":{"type":"string","format":"date-time"}}},"spec":{"$ref":"#/components/schemas/KdcClusterSpec"},"status":{"$ref":"#/components/schemas/KdcClusterStatus"}}},"ActionResult":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}},"DatabasesStatus":{"type":"object","properties":{"enabled":{"type":"boolean","description":"Whether managed databases are available on this installation."}}},"DatabasesConfig":{"type":"object","properties":{"engines":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","example":"postgresql"},"label":{"type":"string"},"versions":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"default":{"type":"boolean"}}}}}}},"cpuOptions":{"type":"array","items":{"type":"string"}},"memoryOptions":{"type":"array","items":{"type":"string"}},"storageOptions":{"type":"array","items":{"type":"string"}}}},"DatabaseList":{"type":"object","properties":{"total":{"type":"integer"},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"},"engine":{"type":"string","enum":["postgresql","mariadb"]},"version":{"type":"string"},"phase":{"type":"string"},"endpoint":{"type":"string"},"externalEndpoint":{"type":"string"},"replicas":{"type":"integer"},"readyInstances":{"type":"integer"},"instances":{"type":"integer"},"cpu":{"type":"string"},"memory":{"type":"string"},"storage":{"type":"string"},"databaseName":{"type":"string"},"username":{"type":"string"},"backupEnabled":{"type":"boolean"},"latestBackup":{"type":["object","null"]},"exposeType":{"type":"string"},"openBaoEngineConfigured":{"type":"boolean"},"conditions":{"type":"array","items":{"type":"object"}},"labels":{"type":"object","additionalProperties":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"deletionTimestamp":{"type":["string","null"]}}}}}},"DatabaseDetail":{"type":"object","properties":{"metadata":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"},"labels":{"type":"object","additionalProperties":{"type":"string"}},"creationTimestamp":{"type":"string","format":"date-time"}}},"spec":{"$ref":"#/components/schemas/KdcDatabaseSpec"},"status":{"$ref":"#/components/schemas/KdcDatabaseStatus"}}},"DatabaseCreated":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"message":{"type":"string"}}},"MessageResult":{"type":"object","properties":{"success":{"type":"boolean"},"message":{"type":"string"}}},"DatabasePassword":{"type":"object","description":"Treat as a secret.","properties":{"username":{"type":"string"},"password":{"type":"string"},"databaseName":{"type":"string"},"engine":{"type":"string"}}},"EventList":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","description":"A Kubernetes event","trimmed.":null}}}},"DatabaseConfigured":{"type":"object","properties":{"success":{"type":"boolean"},"spec":{"type":"object","description":"The fields that were changed."}}},"DatabaseExposure":{"type":"object","properties":{"success":{"type":"boolean"},"enabled":{"type":"boolean"},"type":{"type":"string"},"externalEndpoint":{"type":"string"}}},"DatabaseBackupConfig":{"type":"object","properties":{"success":{"type":"boolean"},"backup":{"type":"object","description":"The stored backup settings."}}},"DatabaseBackupList":{"type":"object","properties":{"engine":{"type":"string"},"backupConfig":{"type":"object"},"backupStatus":{"type":"object"},"destinationPath":{"type":"string"},"backupReady":{"type":"boolean"},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["Physical","Job","Scheduled","Backup"]},"status":{"type":"string"},"createdAt":{"type":"string","format":"date-time"}}}}}},"BackupStarted":{"type":"object","properties":{"name":{"type":"string"},"engine":{"type":"string","enum":["postgresql","mariadb"]}}},"DatabaseSnapshotList":{"type":"object","properties":{"engine":{"type":"string"},"pitrWindow":{"type":["object","null"],"description":"The time range a point-in-time restore can target."},"archivingActive":{"type":"boolean"},"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"kind":{"type":"string","enum":["Backup","PhysicalBackup"]},"ready":{"type":"boolean"},"startedAt":{"type":"string","format":"date-time"},"completedAt":{"type":["string","null"]},"sizeBytes":{"type":["integer","null"]}}}}}},"RestoreStarted":{"type":"object","properties":{"database":{"type":"string"},"backupName":{"type":"string"},"targetTime":{"type":["string","null"]}}},"RestoredCopy":{"type":"object","properties":{"name":{"type":"string"},"sourceDatabaseName":{"type":"string"},"backupName":{"type":"string"}}},"DatabaseCreate":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"engine":{"type":"string","enum":["postgresql","mariadb"],"default":"postgresql"},"version":{"type":"string","default":"16"},"cpu":{"type":"string","default":"1"},"memory":{"type":"string","default":"2Gi"},"storage":{"type":"string","default":"20Gi"},"storageClassName":{"type":"string"},"replicas":{"type":"integer","default":2},"databaseName":{"type":"string","default":"app"},"username":{"type":"string","default":"app"},"parameters":{"type":"object","additionalProperties":{"type":"string"},"description":"Engine configuration parameters."},"backup":{"type":"object","properties":{"enabled":{"type":"boolean"},"schedule":{"type":"string","description":"Cron schedule."},"retentionDays":{"type":"integer"}}},"expose":{"type":"object","properties":{"type":{"type":"string","enum":["internal","loadbalancer","gateway"],"default":"internal","description":"internal (ClusterIP), loadbalancer (an External IP), or gateway (TLS passthrough)."}}},"breakGlass":{"type":"object","properties":{"enableSuperuserAccess":{"type":"boolean"}}}}},"DatabaseCredentialPolicySummary":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"creationTimestamp":{"type":"string","format":"date-time"},"databaseRef":{"type":"string"},"mode":{"type":"string","enum":["static-rotated","dynamic"]},"username":{"type":"string"},"rotation":{"type":"object"},"sync":{"type":"object"},"role":{"type":"string"},"ttl":{"type":"string"},"maxTtl":{"type":"string"},"status":{"type":"object","properties":{"endpoint":{"type":"string"},"username":{"type":"string"},"targetSecretName":{"type":"string"},"lastRotatedTime":{"type":"string","format":"date-time"},"nextRotationTime":{"type":"string","format":"date-time"},"leaseSupported":{"type":"boolean"},"conditions":{"type":"array","items":{"type":"object"}}}}}},"ManagedCertificateSummary":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"creationTimestamp":{"type":"string","format":"date-time"},"type":{"type":"string","enum":["private","public"]},"purpose":{"type":"string","enum":["server","client","mtls","code-signing"]},"dnsNames":{"type":"array","items":{"type":"string"}},"duration":{"type":"string","example":"2160h"},"renewBefore":{"type":"string","example":"360h"},"targetSecretName":{"type":"string"},"status":{"type":"object","properties":{"issuer":{"type":"string"},"certificateSecretName":{"type":"string"},"notBefore":{"type":"string","format":"date-time"},"notAfter":{"type":"string","format":"date-time"},"renewalTime":{"type":"string","format":"date-time"},"conditions":{"type":"array","items":{"type":"object"}}}}}},"BudgetResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/BudgetStatus"}}}]},"ForecastResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/ForecastReport"}}}]},"PricingModel":{"type":"object","description":"Unit prices of a pricing model, as the billing service publishes them.","additionalProperties":true},"BillingProviderInfo":{"type":"object","properties":{"success":{"type":"boolean"},"provider":{"type":"string","example":"stripe"},"mode":{"type":"string"},"organization":{"type":"string"},"availableProviders":{"type":"object","properties":{"stripe":{"type":"boolean"},"whmcs":{"type":"boolean"}}}}},"BillingProjectListResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"projects":{"type":"array","items":{"type":"string"}},"total_count":{"type":"integer"},"filtered_count":{"type":"integer"},"timestamp":{"type":"string"}}}}}]},"BillingProjectOverviewResponse":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","description":"Estimated costs for the project, from usage metrics.","properties":{"namespace":{"type":"string"},"timestamp":{"type":"string"},"billing_summary":{"type":"object","properties":{"billing_period":{"type":"string"},"current_month_total":{"type":"number"},"last_day_spend":{"type":"number"},"total_cost_per_hour":{"type":"number"}}},"compute_instances":{"type":"object","properties":{"cost_per_hour":{"type":"number"},"cpu_cores":{"type":"number"},"memory_gib":{"type":"number"},"running_pods":{"type":"integer"},"running_vms":{"type":"integer"}}},"cost_breakdown":{"type":"object","properties":{"cpu_cost":{"type":"number"},"memory_cost":{"type":"number"},"storage_cost":{"type":"number"},"network_cost":{"type":"number"},"public_ip_cost":{"type":"number"}}},"resource_hours":{"type":"object","properties":{"cpu_hours":{"type":"number"},"memory_hours":{"type":"number"},"storage_hours_by_class":{"type":"object","additionalProperties":{"type":"number"}}}},"storage_and_network":{"type":"object","properties":{"cost_per_hour":{"type":"number"},"total_storage_gib":{"type":"number"},"storage_by_class":{"type":"object","additionalProperties":{"type":"number"}}}}}}}}]},"BillingProjectTrends":{"type":"object","properties":{"namespace":{"type":"string"},"period_days":{"type":"integer"},"start_date":{"type":"string"},"end_date":{"type":"string"},"total_snapshots":{"type":"integer"},"trends":{"type":"array","items":{"type":"object"}}}},"SubscriptionChange":{"type":"object","properties":{"organization":{"type":"string"},"planId":{"type":"string"},"planName":{"type":"string"},"status":{"type":"string","example":"active"}}},"CheckoutSession":{"type":"object","properties":{"checkoutUrl":{"type":"string","format":"uri","description":"Redirect the user here to complete payment."},"sessionId":{"type":"string"}}},"BudgetInput":{"type":"object","required":["amount","currency","thresholds","version"],"additionalProperties":false,"properties":{"amount":{"type":"string","description":"Positive decimal.","example":"500.00"},"currency":{"type":"string","pattern":"^[A-Z]{3}$","example":"EUR"},"thresholds":{"type":"array","minItems":1,"maxItems":10,"items":{"type":"integer","minimum":1,"maximum":1000},"description":"Increasing percentages of the budget that trigger an alert.","example":[50,80,100]},"version":{"type":"integer","minimum":0,"description":"The version read; 0 to create."}}},"AuditEvents":{"type":"object","properties":{"events":{"type":"array","items":{"type":"object","description":"One audit event."}},"query":{"type":"string","description":"The log selector that was run, for example {org=\"acme\"}."},"returned":{"type":"integer"},"limit":{"type":"integer"}}},"Elevation":{"type":"object","properties":{"elevationId":{"type":"string"},"user":{"type":"string"},"org":{"type":"string"},"project":{"type":"string"},"reason":{"type":"string"},"grantedAt":{"type":"string","format":"date-time"},"expiresAt":{"type":"string","format":"date-time"},"ttlSeconds":{"type":"integer"}}},"ApiError":{"type":"object","properties":{"error":{"type":"string","description":"Human-readable error message."},"details":{"description":"Upstream (usually Kubernetes) response, when the error was passed through."}},"required":["error"]},"KubernetesResource":{"type":"object","description":"A Kubernetes object or list as returned by the API server. Lists carry `items` instead of `spec` and `status`.","additionalProperties":true,"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object","additionalProperties":true},"spec":{"type":"object","additionalProperties":true},"status":{"type":"object","additionalProperties":true}}},"KubernetesList":{"type":"object","description":"A Kubernetes list as returned by the API server.","properties":{"apiVersion":{"type":"string"},"kind":{"type":"string","example":"PodList"},"metadata":{"type":"object","properties":{"resourceVersion":{"type":"string"},"continue":{"type":"string"}}},"items":{"type":"array","items":{"$ref":"#/components/schemas/KubernetesResource"}}}},"KubernetesStatus":{"type":"object","description":"A Kubernetes Status, returned with the refusal's HTTP status (for example 403).","properties":{"kind":{"type":"string","const":"Status"},"apiVersion":{"type":"string"},"status":{"type":"string","example":"Failure"},"message":{"type":"string"},"reason":{"type":"string","example":"Forbidden"},"details":{"type":"object"},"code":{"type":"integer","example":403}}},"ValueLabelOption":{"type":"object","description":"A choice for a form field.","properties":{"value":{"type":"string"},"label":{"type":"string"}}},"TreeNode":{"type":"object","description":"A node of a navigation tree. Leaves may carry extra fields such as status.","additionalProperties":true,"properties":{"id":{"oneOf":[{"type":"integer"},{"type":"string"}]},"name":{"type":"string"},"status":{"type":"string"},"children":{"type":"array","items":{"$ref":"#/components/schemas/TreeNode"}}}},"DeleteResult":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"deleted":{"type":"boolean","const":true}}}},"parameters":{"Namespace":{"name":"namespace","in":"path","required":true,"description":"The Project namespace.","schema":{"type":"string","maxLength":63,"pattern":"^[a-z0-9]([-a-z0-9]*[a-z0-9])?$"}},"Name":{"name":"name","in":"path","required":true,"description":"The service instance name.","schema":{"$ref":"#/components/schemas/ResourceName"}},"DataPlaneClusterName":{"name":"name","in":"path","required":true,"description":"The KdcCluster name in this Project.","schema":{"$ref":"#/components/schemas/ResourceName"}},"Child":{"name":"child","in":"path","required":true,"description":"The name of the operation, binding, credential policy or backup record.","schema":{"$ref":"#/components/schemas/ResourceName"}},"CardId":{"name":"cardId","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9][a-z0-9-]{0,62}$"}},"CardRevision":{"name":"revision","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$"}},"Organization":{"name":"organization","in":"path","required":true,"schema":{"type":"string","pattern":"^[a-z0-9]([-a-z0-9]{0,61}[a-z0-9])?$"}},"IdempotencyKey":{"name":"Idempotency-Key","in":"header","required":true,"schema":{"type":"string","minLength":8,"maxLength":128}},"From":{"name":"from","in":"query","required":false,"description":"RFC3339 UTC, whole-minute boundary. Inclusive.","schema":{"type":"string","format":"date-time"}},"To":{"name":"to","in":"query","required":false,"description":"RFC3339 UTC, whole-minute boundary. Exclusive. Maximum span 31 days.","schema":{"type":"string","format":"date-time"}},"GroupBy":{"name":"groupBy","in":"query","required":false,"description":"Comma-separated allowlisted dimension keys, at most 8.","schema":{"type":"string"}},"Cursor":{"name":"cursor","in":"query","required":false,"schema":{"type":"string","maxLength":256}},"Limit":{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":1000,"default":500}},"VolumeName":{"name":"name","in":"path","required":true,"description":"Name of the volume (PVC or DataVolume).","schema":{"type":"string"}},"CloneSource":{"name":"source","in":"query","required":true,"description":"PVC to clone from.","schema":{"type":"string"}},"CloneStorageClass":{"name":"storage","in":"query","required":true,"description":"Storage class for the new volume.","schema":{"type":"string"}},"VolumeSize":{"name":"size","in":"query","required":true,"description":"Volume size.","schema":{"type":"string","example":"20Gi"}},"SecretName":{"name":"name","in":"path","required":true,"description":"ManagedSecret name.","schema":{"type":"string","example":"db-password"}},"KmsKeyName":{"name":"name","in":"path","required":true,"description":"KMSKey name (DNS-1123 subdomain).","schema":{"type":"string","example":"app-data"}},"ClusterName":{"name":"name","in":"path","required":true,"description":"Managed cluster (KdcCluster) name.","schema":{"type":"string","example":"prod"}},"WorkerPoolName":{"name":"pool","in":"path","required":true,"description":"Name of the worker pool.","schema":{"type":"string","example":"workers"}},"CredentialPolicyName":{"name":"name","in":"path","required":true,"description":"DatabaseCredentialPolicy name.","schema":{"type":"string","example":"app-user"}},"CertificateName":{"name":"name","in":"path","required":true,"description":"ManagedCertificate name (DNS-1123 subdomain).","schema":{"type":"string","example":"api-tls"}},"AuditService":{"name":"service","in":"query","description":"Only events from this service, e.g. secrets, certificates, kms, db-credentials, org-admin.","schema":{"type":"string","pattern":"^[a-z][a-z0-9-]{0,40}$"}},"AuditActor":{"name":"actor","in":"query","description":"Substring of the actor's username, email or subject.","schema":{"type":"string"}},"AuditResult":{"name":"result","in":"query","description":"Only events with this outcome.","schema":{"type":"string","enum":["allowed","denied","error","success","failure"]}},"AuditSince":{"name":"since","in":"query","description":"Epoch seconds or RFC 3339.","schema":{"type":"string"}},"AuditUntil":{"name":"until","in":"query","description":"Epoch seconds or RFC 3339.","schema":{"type":"string"}},"AuditLimit":{"name":"limit","in":"query","description":"Most events to return (default 500, at most 5000; the CSV export defaults to 5000).","schema":{"type":"integer","minimum":1,"maximum":5000,"default":500}},"ProjectNamespace":{"name":"namespace","in":"path","required":true,"description":"Project namespace, `<organization>-<project>`.","schema":{"type":"string","example":"acme-web"}},"ResourceNameParam":{"name":"name","in":"path","required":true,"description":"Name of the resource in the project namespace.","schema":{"type":"string"}},"OrganizationParam":{"name":"org","in":"path","required":true,"description":"Organization name (the organization namespace).","schema":{"type":"string","example":"acme"}},"ProjectParam":{"name":"project","in":"path","required":true,"description":"Project name within the organization (not the namespace).","schema":{"type":"string","example":"web"}}},"responses":{"Error":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"BadRequest":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Unauthenticated":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Forbidden":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"NotFound":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"Conflict":{"description":"Revision mismatch, reused idempotency key with a different body, an edit\nto immutable data, a UID mismatch, a commerce-owner conflict, an active\nhold, or an outstanding provider handoff.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"ValidationFailed":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"EvidenceUnavailable":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"}}}},"BrandingImage":{"description":"The image. Falls back to the stock asset when none is configured.","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"OrgError":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"}}}},"ApiError":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"}}}},"KubernetesError":{"description":"Kubernetes refused or failed the request; its Status object and status code are passed through (for example 403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"}}}},"EnvelopeError":{"description":"Error.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}}}}},"TextError":{"description":"Error, as plain text.","content":{"text/plain":{"schema":{"type":"string"}}}},"ResourceYaml":{"description":"The resource manifest as YAML.","content":{"text/plain":{"schema":{"type":"string"}}}}},"headers":{"CacheControl":{"description":"Always `no-store`.","schema":{"type":"string","const":"no-store"}}},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT","description":"Keycloak access token for your organization realm."},"keycloak":{"type":"oauth2","description":"Sign in with your Kube-DC account. Enter your organization at the top of the reference page first.","flows":{"authorizationCode":{"authorizationUrl":"https://login.kube-dc.cloud/realms/your-organization/protocol/openid-connect/auth","tokenUrl":"/reference/oauth/your-organization/token","scopes":{"openid":"Sign in"}}}}},"requestBodies":{"ResourceYaml":{"required":true,"description":"Full resource manifest. Replaces the stored object.","content":{"application/yaml":{"schema":{"type":"string"}}}}}},"security":[{"bearerAuth":[]},{"keycloak":["openid"]}],"tags":[{"name":"Virtual Machines","description":"Create, start, stop and inspect KubeVirt virtual machines, their metrics and node placement."},{"name":"VM Configuration","description":"Change CPU, memory, GPU, probes and console access of an existing VM."},{"name":"Volumes","description":"Persistent volumes for VMs and workloads: create, clone, resize and delete."},{"name":"Accelerators","description":"GPU capability, inventory and quota per project, and shared GPU workloads."},{"name":"Workloads","description":"Pods, Deployments, StatefulSets, DaemonSets, Jobs and ReplicaSets in a project, with their logs."},{"name":"Services & Ingress","description":"Kubernetes Services and Ingresses in a project."},{"name":"ConfigMaps & Kubernetes Secrets","description":"Plain Kubernetes ConfigMaps and Secrets. For secrets stored in OpenBao, see Secrets."},{"name":"Managed Clusters","description":"Managed Kubernetes clusters: lifecycle, worker pools, upgrades, etcd snapshots and kubeconfig."},{"name":"Cloud Shell","description":"Browser terminals with kubectl preconfigured for a project."},{"name":"Networking","description":"External IPs, Floating IPs, LoadBalancer services and routed networks."},{"name":"Object Storage","description":"S3-compatible buckets, access keys and key rotation."},{"name":"Databases","description":"Managed PostgreSQL and MariaDB databases (KdcDatabase): lifecycle, backups and users."},{"name":"Database Credentials","description":"Rotated or short-lived database users issued through OpenBao."},{"name":"Managed Services: Catalog","description":"Service classes and plans that can be ordered."},{"name":"Managed Services: Instances","description":"Managed service instances in a project."},{"name":"Managed Services: Operations","description":"Long-running operations on an instance, such as upgrades and restarts."},{"name":"Managed Services: Bindings","description":"Credentials published from an instance to an application."},{"name":"Managed Services: Credential policies","description":"How bound credentials are rotated."},{"name":"Managed Services: Backups","description":"Backups and restores of an instance."},{"name":"Managed Services: Replication groups","description":"Replicated instances across projects."},{"name":"Managed Services: Data planes","description":"Project clusters granted to run managed services (remote placement)."},{"name":"Secrets","description":"Secrets stored in OpenBao with version history, optionally synced into Kubernetes Secrets."},{"name":"Certificates","description":"TLS certificates issued from the organization CA or a public issuer, renewed automatically."},{"name":"KMS","description":"Encryption keys for application-level encrypt and decrypt."},{"name":"Audit","description":"Who accessed secrets, certificates, keys and database credentials."},{"name":"Organization","description":"Projects, users, groups, roles, quotas and settings of your organization."},{"name":"Registration","description":"Self-service sign-up of new organizations."},{"name":"Billing","description":"Plans, subscriptions, add-ons, quota usage, pay-as-you-go and budgets."},{"name":"Billing: Quotes","description":"Prices for a managed service before it is ordered."},{"name":"Billing: Reports","description":"Usage and estimated cost grouped by project, product or period."},{"name":"Billing: Budgets","description":"Advisory monthly budgets and month-end forecasts."},{"name":"Billing: Producers","description":"Usage producers that report metered consumption."},{"name":"Platform","description":"Public installation metadata, branding and feature flags."}],"paths":{"/capabilities/{namespace}/gpus":{"get":{"tags":["Accelerators"],"operationId":"getGpuCapabilities","description":"What GPU work the project can run now. Covers the GPU models offered, their health and free capacity, and how much of the project's GPU quota is used.","summary":"Get Project-scoped GPU capability, health, capacity, and quota state","parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"},"description":"Project backing namespace used for authorization."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUCapabilitiesResponse"},"example":{"success":true,"data":{"namespace":"acme-training","creationEnabled":true,"vmCreationEnabled":false,"vmGPUAvailable":false,"profiles":[{"id":"nvidia-v100-hami","displayName":"NVIDIA V100 Shared","vendor":"nvidia","workload":"pod","allocation":"hami","memoryMiB":32768,"isolation":"cooperative","liveMigratable":false,"quotaDimension":"shares","request":{"minMemoryMiB":1024,"maxMemoryMiB":32768,"memoryStepMiB":1024,"minCorePercent":5,"maxCorePercent":100,"coreStepPercent":5,"allowCustom":true,"presets":[{"id":"standard","displayName":"Standard","memoryMiB":8192,"corePercent":25,"default":true}]},"capacity":{"shares":20,"devices":2},"requested":{"shares":1,"memoryMiB":8192,"corePercent":25},"available":true,"canCreate":true,"willQueue":false,"reasonCodes":[],"health":"Ready"}],"quota":{"nvidia-v100-hami":{"shares":{"used":"1","hard":"2","available":"1","scope":"project"},"memoryMiB":{"used":"8192","hard":"16384","available":"8192","scope":"project"},"corePercent":{"used":"25","hard":"50","available":"25","scope":"project"}}},"quotaScopes":{"project":{"nvidia-v100-hami":{"shares":{"used":"1","hard":"2","available":"1"}}},"organization":{"nvidia-v100-hami":{"shares":{"used":"1","hard":"4","available":"3"}}}},"lastUpdated":"2026-07-15T05:00:00.000Z"}}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"403":{"description":"Project access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"503":{"description":"GPU discovery unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}}}}},"/capabilities/{namespace}/gpus/shared-workloads/preview":{"post":{"tags":["Accelerators"],"operationId":"previewSharedGpuWorkload","description":"Checks a shared GPU workload request against quota and capacity without creating anything, and shows what would be created.","summary":"Preview a canonical fixed-SKU Shared GPU workload","parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"},"description":"Project backing namespace used for authorization."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUSharedWorkloadRequest"},"example":{"profileId":"nvidia-v100-hami","name":"inference","image":"nvcr.io/nvidia/pytorch:24.08-py3","replicas":2,"memoryMiB":8192,"corePercent":25,"allowQueue":false}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUSharedWorkloadPreviewResponse"},"example":{"success":true,"data":{"name":"web-1","request":{"replicas":2,"shares":1,"memoryMiB":8192,"corePercent":75},"totals":{"replicas":2,"shares":1,"memoryMiB":8192,"corePercent":75},"queued":true}}}}},"403":{"description":"Namespace create access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"404":{"description":"Shared GPU creation is disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"409":{"description":"Entitlement, quota, capacity confirmation, or readiness blocks creation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"422":{"description":"Invalid fixed-SKU workload request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"503":{"description":"Shared GPU workload preview unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}}}}},"/capabilities/{namespace}/gpus/shared-workloads":{"post":{"tags":["Accelerators"],"operationId":"createSharedGpuWorkload","description":"Creates a workload on a shared GPU from a fixed size (SKU). The backend creates and owns the underlying objects, so the request stays within the project's GPU quota.","summary":"Create a backend-owned canonical Shared GPU workload","parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"},"description":"Project backing namespace used for authorization."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUSharedWorkloadRequest"},"example":{"profileId":"nvidia-v100-hami","name":"inference","image":"nvcr.io/nvidia/pytorch:24.08-py3","replicas":2,"memoryMiB":8192,"corePercent":25,"allowQueue":false}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUSharedWorkloadCreateResponse"},"example":{"success":true,"data":{"namespace":"acme-web","name":"web-1","request":{"replicas":2,"shares":1,"memoryMiB":8192,"corePercent":75},"totals":{"replicas":2,"shares":1,"memoryMiB":8192,"corePercent":75},"queued":true,"created":true}}}}},"201":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUSharedWorkloadCreateResponse"},"example":{"success":true,"data":{"namespace":"acme-web","name":"web-1","request":{"replicas":2,"shares":1,"memoryMiB":8192,"corePercent":75},"totals":{"replicas":2,"shares":1,"memoryMiB":8192,"corePercent":75},"queued":true,"created":true}}}}},"403":{"description":"Namespace create access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"404":{"description":"Shared GPU creation is disabled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"409":{"description":"Entitlement, quota, queue confirmation, or managed-name conflict","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"422":{"description":"Invalid or admission-rejected fixed-SKU workload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"503":{"description":"Shared GPU workload creation unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}}}}},"/capabilities/{namespace}/gpus/shared-workloads/{name}":{"delete":{"tags":["Accelerators"],"operationId":"releaseSharedGpuWorkload","description":"Deletes a shared GPU workload created through this API and frees its GPU share.","summary":"Release a backend-owned Shared GPU workload","parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"},"description":"Project backing namespace used for authorization."},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Managed workload name."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUSharedWorkloadReleaseResponse"},"example":{"success":true,"data":{"namespace":"acme-web","name":"web-1","released":true}}}}},"403":{"description":"Namespace delete access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"409":{"description":"The named Deployment is not a kube-dc Shared GPU workload","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"422":{"description":"Invalid workload name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}},"503":{"description":"Shared GPU workload release unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUError"},"example":{"success":false,"status":503,"error":{"code":"GPU_DISCOVERY_UNAVAILABLE","message":"GPU capability discovery is unavailable"}}}}}}}},"/billing/quota/{namespace}":{"get":{"tags":["Accelerators","Billing"],"operationId":"getProjectQuota","description":"The project's and the organization's quota limits and live usage, including GPU dimensions by profile.","summary":"Get live project and organization quota including stable GPU dimensions","parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"},"description":"Project backing namespace used for authorization."}],"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUQuotaSummaryResponse"},"example":{"success":true,"message":"Quota summary retrieved","timestamp":"2026-07-15T05:00:00.000Z","data":{"namespace":"acme-training","organization":"acme","limitRange":null,"project":{"cpu":{"used":"1","hard":null,"available":null},"memory":{"used":"2Gi","hard":null,"available":null},"storage":{"used":"10Gi","hard":null,"available":null},"pods":{"used":"3","hard":null,"available":null},"perProjectQuotaSet":false,"lastUpdated":"2026-07-15T04:59:00.000Z","accelerators":{"nvidia-v100-hami":{"shares":{"used":"1","hard":null,"available":null},"memoryMiB":{"used":"8192","hard":null,"available":null},"corePercent":{"used":"25","hard":null,"available":null}}}},"org":{"cpu":{"used":"2","hard":"16","available":"14","enforcedHard":"16.25","enforcedAvailable":"14.25"},"memory":{"used":"4Gi","hard":"64Gi","available":"60Gi","enforcedHard":"66.234Gi","enforcedAvailable":"62.234Gi"},"storage":{"used":"20Gi","hard":"500Gi","available":"480Gi"},"pods":{"used":"6","hard":"100","available":"94"},"accelerators":{"nvidia-v100-hami":{"shares":{"used":"1","hard":"2","available":"1"},"memoryMiB":{"used":"8192","hard":"16384","available":"8192"},"corePercent":{"used":"25","hard":"50","available":"25"}}},"lastUpdated":"2026-07-15T04:59:00.000Z"}}}}}},"401":{"description":"Authentication required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandardError"},"example":{"success":false,"status":401,"error":"Authentication required"}}}},"403":{"description":"Namespace access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandardError"},"example":{"success":false,"status":403,"error":"Access denied"}}}},"500":{"description":"Quota summary unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandardError"},"example":{"success":false,"status":500,"error":"Failed to fetch quota summary"}}}}}}},"/manage-organization/projects/{projectId}/quota/preview":{"post":{"tags":["Accelerators","Organization"],"operationId":"previewProjectAcceleratorQuota","description":"Shows what a new GPU limit for the project would change, checked against the organization's quota and the GPU catalog. Nothing is changed. Requires org-admin.","summary":"Preview a stable-profile project accelerator cap without mutation","parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"},"description":"Stable Project ID within the caller's Organization."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUQuotaPreviewRequest"},"example":{"accelerators":{"nvidia-v100-hami":{"shares":4,"memoryMiB":32768,"corePercent":100}}}}}},"responses":{"200":{"description":"Successful response","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUQuotaPreviewResponse"},"example":{"success":true,"timestamp":"2026-07-15T05:00:00.000Z","data":{"accelerators":{"nvidia-v100-hami":{"shares":2,"memoryMiB":16384,"corePercent":50}},"pooled":false,"action":"update"}}}}},"400":{"description":"Invalid or over-entitlement accelerator cap","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GPUQuotaMutationError"},"example":{"success":false,"error":"Project accelerator cap exceeds the organization entitlement","code":"ORGANIZATION_ACCELERATOR_QUOTA_EXCEEDED","details":{"violations":[{"profileId":"nvidia-v100-hami","field":"shares","requested":"3","organizationHard":"2"}]}}}}},"403":{"description":"Organization administrator role required","content":{"application/json":{"schema":{"$ref":"#/components/schemas/StandardError"},"example":{"success":false,"status":403,"error":"Organization administrator role required to manage project quotas"}}}}}}},"/object-storage/{namespace}/buckets/{name}/key-rotations":{"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"createObjectBucketKeyRotation","tags":["Object Storage"],"summary":"Request an idempotent UID-bound archive key rotation","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"idempotencyKey":{"type":"string","minLength":1,"maxLength":128},"claimUID":{"type":"string","minLength":1,"maxLength":64},"sourceSecretUID":{"type":"string","minLength":1,"maxLength":64},"gracePeriodSeconds":{"type":"integer","minimum":60,"maximum":86400,"default":300}},"required":["idempotencyKey","claimUID","sourceSecretUID"]},"example":{"idempotencyKey":"7f9c2ba4-e88f-4c2a-9a3b-1d2e3f4a5b6c","claimUID":"5d1c7e4a-2b3f-4c5d-8e9f-0a1b2c3d4e5f","sourceSecretUID":"9a8b7c6d-5e4f-4a3b-8c2d-1e0f9a8b7c6d","gracePeriodSeconds":300}}}},"responses":{"200":{"description":"Rotation reference and status; no key material","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"rotation":{"$ref":"#/components/schemas/ObjectBucketRotation"}},"required":["rotation"]},"example":{"rotation":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","generation":1,"createdAt":"2026-10-01T09:30:00Z","deleting":true,"spec":{"projectRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"projectNamespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","claimRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sourceSecretUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","gracePeriodSeconds":300,"abandon":{"reason":"Ready"}},"status":{"phase":"Pending","objectBucketUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rgwUser":"rgw-user","sourceResourceVersion":"1","publishedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","retiringKeys":[{"rotationUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rotationName":"web-1","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","abandonedAt":"2026-10-01T09:30:00Z"}],"untrackedKeys":1,"abandon":{"outcome":"Deferred","observedAt":"2026-10-01T09:30:00Z","abandonedAt":"2026-10-01T09:30:00Z","result":"OldKeyRetained","verified":true,"oldKeyState":"Present","blockedReason":"Done.","blockedMessage":"Done.","stalledReason":"Done.","stalledSince":"2026-10-01T09:30:00Z","retirement":"Recorded"},"conditions":[{"type":"Ready","status":"True","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z","reason":"Ready","message":"Done."}]}}}}}},"202":{"description":"Rotation reference and status; no key material","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"rotation":{"$ref":"#/components/schemas/ObjectBucketRotation"}},"required":["rotation"]},"example":{"rotation":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","generation":1,"createdAt":"2026-10-01T09:30:00Z","deleting":true,"spec":{"projectRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"projectNamespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","claimRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sourceSecretUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","gracePeriodSeconds":300,"abandon":{"reason":"Ready"}},"status":{"phase":"Pending","objectBucketUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rgwUser":"rgw-user","sourceResourceVersion":"1","publishedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","retiringKeys":[{"rotationUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rotationName":"web-1","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","abandonedAt":"2026-10-01T09:30:00Z"}],"untrackedKeys":1,"abandon":{"outcome":"Deferred","observedAt":"2026-10-01T09:30:00Z","abandonedAt":"2026-10-01T09:30:00Z","result":"OldKeyRetained","verified":true,"oldKeyState":"Present","blockedReason":"Done.","blockedMessage":"Done.","stalledReason":"Done.","stalledSince":"2026-10-01T09:30:00Z","retirement":"Recorded"},"conditions":[{"type":"Ready","status":"True","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z","reason":"Ready","message":"Done."}]}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Invalid request"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Unauthenticated"}}}},"403":{"description":"Caller lacks Kubernetes permission","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Your role does not allow this."}}}},"404":{"description":"Resource absent","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Resource absent"}}}},"409":{"description":"Incarnation or idempotency conflict","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Incarnation or idempotency conflict"}}}},"503":{"description":"Provider unavailable","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Provider unavailable"}}}}},"description":"Requests a rotation of the key that encrypts the bucket's archive. A request repeated with the same `idempotencyKey` returns the original rotation instead of starting another."},"get":{"operationId":"listObjectBucketKeyRotations","tags":["Object Storage"],"summary":"List rotations for the current claim incarnation","responses":{"200":{"description":"Current claim incarnation rotations","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"rotations":{"type":"array","items":{"$ref":"#/components/schemas/ObjectBucketRotation"}}},"required":["rotations"]},"example":{"rotations":[{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","generation":1,"createdAt":"2026-10-01T09:30:00Z","deleting":true,"spec":{"projectRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"projectNamespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","claimRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sourceSecretUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","gracePeriodSeconds":300,"abandon":{"reason":"Ready"}},"status":{"phase":"Pending","objectBucketUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rgwUser":"rgw-user","sourceResourceVersion":"1","publishedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","retiringKeys":[{"rotationUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rotationName":"web-1","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","abandonedAt":"2026-10-01T09:30:00Z"}],"untrackedKeys":1,"abandon":{"outcome":"Deferred","observedAt":"2026-10-01T09:30:00Z","abandonedAt":"2026-10-01T09:30:00Z","result":"OldKeyRetained","verified":true,"oldKeyState":"Present","blockedReason":"Done.","blockedMessage":"Done.","stalledReason":"Done.","stalledSince":"2026-10-01T09:30:00Z","retirement":"Recorded"},"conditions":[{"type":"Ready","status":"True","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z","reason":"Ready","message":"Done."}]}}]}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Invalid request"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Unauthenticated"}}}},"403":{"description":"Caller lacks Kubernetes permission","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Your role does not allow this."}}}},"404":{"description":"Resource absent","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Resource absent"}}}},"409":{"description":"Incarnation or idempotency conflict","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Incarnation or idempotency conflict"}}}},"503":{"description":"Provider unavailable","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Provider unavailable"}}}}},"description":"Key rotations requested for the bucket's current claim, newest first. A recreated bucket with the same name starts a fresh history."}},"/object-storage/{namespace}/buckets/{name}/key-rotations/{rotation}":{"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"rotation","in":"path","required":true,"schema":{"type":"string"}}],"get":{"operationId":"getObjectBucketKeyRotation","tags":["Object Storage"],"summary":"Read one durable rotation request","responses":{"200":{"description":"Rotation reference and status; no key material","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"rotation":{"$ref":"#/components/schemas/ObjectBucketRotation"}},"required":["rotation"]},"example":{"rotation":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","generation":1,"createdAt":"2026-10-01T09:30:00Z","deleting":true,"spec":{"projectRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"projectNamespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","claimRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sourceSecretUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","gracePeriodSeconds":300,"abandon":{"reason":"Ready"}},"status":{"phase":"Pending","objectBucketUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rgwUser":"rgw-user","sourceResourceVersion":"1","publishedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","retiringKeys":[{"rotationUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rotationName":"web-1","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","abandonedAt":"2026-10-01T09:30:00Z"}],"untrackedKeys":1,"abandon":{"outcome":"Deferred","observedAt":"2026-10-01T09:30:00Z","abandonedAt":"2026-10-01T09:30:00Z","result":"OldKeyRetained","verified":true,"oldKeyState":"Present","blockedReason":"Done.","blockedMessage":"Done.","stalledReason":"Done.","stalledSince":"2026-10-01T09:30:00Z","retirement":"Recorded"},"conditions":[{"type":"Ready","status":"True","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z","reason":"Ready","message":"Done."}]}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Invalid request"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Unauthenticated"}}}},"403":{"description":"Caller lacks Kubernetes permission","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Your role does not allow this."}}}},"404":{"description":"Resource absent","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Resource absent"}}}},"409":{"description":"Incarnation or idempotency conflict","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Incarnation or idempotency conflict"}}}},"503":{"description":"Provider unavailable","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Provider unavailable"}}}}},"description":"One rotation request with its progress."}},"/object-storage/{namespace}/buckets/{name}/key-rotations/{rotation}/abandon":{"parameters":[{"name":"namespace","in":"path","required":true,"schema":{"type":"string"}},{"name":"name","in":"path","required":true,"schema":{"type":"string"}},{"name":"rotation","in":"path","required":true,"schema":{"type":"string"}}],"post":{"operationId":"abandonObjectBucketKeyRotation","tags":["Object Storage"],"summary":"Abandon a stalled rotation without revoking the old key","description":"Sets spec.abandon once on the named rotation incarnation. A rotation without a replacement key is cancelled; one creating or publishing it finishes publication first. One revoking the old key is not interrupted and may succeed instead (outcome Superseded), unless it lost its intent or a check before revocation (claim Secret changed, new key rejected, intent replaced, consumer reads or the registry write refused) has failed for ten minutes. A step that keeps failing with evidence for ten minutes is abandoned from what the claim Secret and RGW show (verified only when the Secret holds a new key RGW accepts); a claim or Secret gone or replaced for ten minutes is abandoned unverified. The rotation ends Abandoned, reporting which keys stay valid; the next successful rotation retires the keys it left. Re-sending the same reason returns 200; another reason, another incarnation or a finished rotation returns 409.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"rotationUID":{"type":"string","minLength":1,"maxLength":64},"reason":{"type":"string","minLength":1,"maxLength":256}},"required":["rotationUID","reason"]},"example":{"rotationUID":"3c4d5e6f-7a8b-4c9d-8e0f-1a2b3c4d5e6f","reason":"Old key still used by the nightly export job."}}}},"responses":{"200":{"description":"Rotation reference and status; no key material","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"rotation":{"$ref":"#/components/schemas/ObjectBucketRotation"}},"required":["rotation"]},"example":{"rotation":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","generation":1,"createdAt":"2026-10-01T09:30:00Z","deleting":true,"spec":{"projectRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"projectNamespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","claimRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sourceSecretUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","gracePeriodSeconds":300,"abandon":{"reason":"Ready"}},"status":{"phase":"Pending","objectBucketUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rgwUser":"rgw-user","sourceResourceVersion":"1","publishedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","retiringKeys":[{"rotationUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rotationName":"web-1","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","abandonedAt":"2026-10-01T09:30:00Z"}],"untrackedKeys":1,"abandon":{"outcome":"Deferred","observedAt":"2026-10-01T09:30:00Z","abandonedAt":"2026-10-01T09:30:00Z","result":"OldKeyRetained","verified":true,"oldKeyState":"Present","blockedReason":"Done.","blockedMessage":"Done.","stalledReason":"Done.","stalledSince":"2026-10-01T09:30:00Z","retirement":"Recorded"},"conditions":[{"type":"Ready","status":"True","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z","reason":"Ready","message":"Done."}]}}}}}},"202":{"description":"Rotation reference and status; no key material","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"rotation":{"$ref":"#/components/schemas/ObjectBucketRotation"}},"required":["rotation"]},"example":{"rotation":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","generation":1,"createdAt":"2026-10-01T09:30:00Z","deleting":true,"spec":{"projectRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"projectNamespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","claimRef":{"namespace":"acme-web","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sourceSecretUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","gracePeriodSeconds":300,"abandon":{"reason":"Ready"}},"status":{"phase":"Pending","objectBucketUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rgwUser":"rgw-user","sourceResourceVersion":"1","publishedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","retiringKeys":[{"rotationUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","rotationName":"web-1","previousFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","currentFingerprint":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","abandonedAt":"2026-10-01T09:30:00Z"}],"untrackedKeys":1,"abandon":{"outcome":"Deferred","observedAt":"2026-10-01T09:30:00Z","abandonedAt":"2026-10-01T09:30:00Z","result":"OldKeyRetained","verified":true,"oldKeyState":"Present","blockedReason":"Done.","blockedMessage":"Done.","stalledReason":"Done.","stalledSince":"2026-10-01T09:30:00Z","retirement":"Recorded"},"conditions":[{"type":"Ready","status":"True","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z","reason":"Ready","message":"Done."}]}}}}}},"400":{"description":"Invalid request","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Invalid request"}}}},"401":{"description":"Unauthenticated","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Unauthenticated"}}}},"403":{"description":"Caller lacks Kubernetes permission","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Your role does not allow this."}}}},"404":{"description":"Resource absent","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Resource absent"}}}},"409":{"description":"Incarnation or idempotency conflict","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Incarnation or idempotency conflict"}}}},"503":{"description":"Provider unavailable","content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"properties":{"error":{"type":"string"}},"required":["error"]},"example":{"error":"Provider unavailable"}}}}}}},"/managed-services/{namespace}/replication-groups":{"get":{"tags":["Managed Services: Replication groups"],"operationId":"listReplicationGroups","summary":"Replication groups in this Project.","parameters":[{"$ref":"#/components/parameters/Namespace"}],"responses":{"200":{"description":"Current topology state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplicationGroupList"},"example":{"items":[{"apiVersion":"v1","kind":"ReplicationGroup","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{"family":"postgresql","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","primary":"primary"},"status":{"activeChange":{"epoch":1,"expiresAt":"2026-10-01T09:30:00Z","homeHub":"home-hub","intent":{"epoch":1,"groupRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"homeHub":"home-hub","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","requestedGeneration":1,"sequence":1,"source":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"strategy":"Planned","target":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}},"name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"aliases":[{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"epoch":1,"primaryUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","ready":true,"reason":"Ready","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"bootstrapPrimaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentials":{"authorityRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"caExpiresAt":"2026-10-01T09:30:00Z","profile":{"database":"app","owner":"owner","readonly":true},"revision":"9f86d081884c7d659a2feaa0c55ad015"},"epoch":1,"fences":[{"actor":"jdoe","changeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"confirmedAt":"2026-10-01T09:30:00Z","epoch":1,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","member":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"method":"RunnerAcknowledged","rebuiltNativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"homeHub":"home-hub","members":[{"archiveRevision":"7","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentialRevision":"7","credentials":{"authorityRevision":"9f86d081884c7d659a2feaa0c55ad015","expiresAt":"2026-10-01T09:30:00Z","materialRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"namespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","projections":[{"kind":"CA","name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"sequence":1},"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"delaySeconds":3600,"groupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","lastObservedAt":"2026-10-01T09:30:00Z","nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"observedEpoch":1,"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"promotable":true,"role":"Primary","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"observedGeneration":1,"primaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sequence":1}}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Replication groups in the project. A group ties instances in different projects into one primary and its mirrors."},"post":{"tags":["Managed Services: Replication groups"],"operationId":"createReplicationGroup","summary":"Create a plan-qualified replication group.","parameters":[{"$ref":"#/components/parameters/Namespace"}],"responses":{"200":{"description":"Current topology state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplicationGroup"},"example":{"apiVersion":"v1","kind":"ReplicationGroup","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{"family":"postgresql","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","primary":"primary"},"status":{"activeChange":{"epoch":1,"expiresAt":"2026-10-01T09:30:00Z","homeHub":"home-hub","intent":{"epoch":1,"groupRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"homeHub":"home-hub","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","requestedGeneration":1,"sequence":1,"source":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"strategy":"Planned","target":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}},"name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"aliases":[{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"epoch":1,"primaryUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","ready":true,"reason":"Ready","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"bootstrapPrimaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentials":{"authorityRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"caExpiresAt":"2026-10-01T09:30:00Z","profile":{"database":"app","owner":"owner","readonly":true},"revision":"9f86d081884c7d659a2feaa0c55ad015"},"epoch":1,"fences":[{"actor":"jdoe","changeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"confirmedAt":"2026-10-01T09:30:00Z","epoch":1,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","member":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"method":"RunnerAcknowledged","rebuiltNativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"homeHub":"home-hub","members":[{"archiveRevision":"7","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentialRevision":"7","credentials":{"authorityRevision":"9f86d081884c7d659a2feaa0c55ad015","expiresAt":"2026-10-01T09:30:00Z","materialRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"namespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","projections":[{"kind":"CA","name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"sequence":1},"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"delaySeconds":3600,"groupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","lastObservedAt":"2026-10-01T09:30:00Z","nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"observedEpoch":1,"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"promotable":true,"role":"Primary","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"observedGeneration":1,"primaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sequence":1}}}}},"201":{"description":"Current topology state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplicationGroup"},"example":{"apiVersion":"v1","kind":"ReplicationGroup","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{"family":"postgresql","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","primary":"primary"},"status":{"activeChange":{"epoch":1,"expiresAt":"2026-10-01T09:30:00Z","homeHub":"home-hub","intent":{"epoch":1,"groupRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"homeHub":"home-hub","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","requestedGeneration":1,"sequence":1,"source":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"strategy":"Planned","target":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}},"name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"aliases":[{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"epoch":1,"primaryUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","ready":true,"reason":"Ready","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"bootstrapPrimaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentials":{"authorityRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"caExpiresAt":"2026-10-01T09:30:00Z","profile":{"database":"app","owner":"owner","readonly":true},"revision":"9f86d081884c7d659a2feaa0c55ad015"},"epoch":1,"fences":[{"actor":"jdoe","changeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"confirmedAt":"2026-10-01T09:30:00Z","epoch":1,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","member":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"method":"RunnerAcknowledged","rebuiltNativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"homeHub":"home-hub","members":[{"archiveRevision":"7","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentialRevision":"7","credentials":{"authorityRevision":"9f86d081884c7d659a2feaa0c55ad015","expiresAt":"2026-10-01T09:30:00Z","materialRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"namespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","projections":[{"kind":"CA","name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"sequence":1},"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"delaySeconds":3600,"groupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","lastObservedAt":"2026-10-01T09:30:00Z","nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"observedEpoch":1,"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"promotable":true,"role":"Primary","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"observedGeneration":1,"primaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sequence":1}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateReplicationGroupRequest"},"example":{"name":"orders-replication","idempotencyKey":"1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e","family":"postgresql","mode":"PostgresStreaming","primary":"orders"}}}},"description":"Creates a replication group for instances on a plan that supports replication."}},"/managed-services/{namespace}/replication-groups/{name}":{"get":{"tags":["Managed Services: Replication groups"],"operationId":"getReplicationGroup","summary":"Committed and desired topology, members and aliases.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"Current topology state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplicationGroup"},"example":{"apiVersion":"v1","kind":"ReplicationGroup","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{"family":"postgresql","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","primary":"primary"},"status":{"activeChange":{"epoch":1,"expiresAt":"2026-10-01T09:30:00Z","homeHub":"home-hub","intent":{"epoch":1,"groupRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"homeHub":"home-hub","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","requestedGeneration":1,"sequence":1,"source":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"strategy":"Planned","target":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}},"name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"aliases":[{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"epoch":1,"primaryUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","ready":true,"reason":"Ready","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"bootstrapPrimaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentials":{"authorityRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"caExpiresAt":"2026-10-01T09:30:00Z","profile":{"database":"app","owner":"owner","readonly":true},"revision":"9f86d081884c7d659a2feaa0c55ad015"},"epoch":1,"fences":[{"actor":"jdoe","changeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"confirmedAt":"2026-10-01T09:30:00Z","epoch":1,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","member":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"method":"RunnerAcknowledged","rebuiltNativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"homeHub":"home-hub","members":[{"archiveRevision":"7","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentialRevision":"7","credentials":{"authorityRevision":"9f86d081884c7d659a2feaa0c55ad015","expiresAt":"2026-10-01T09:30:00Z","materialRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"namespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","projections":[{"kind":"CA","name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"sequence":1},"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"delaySeconds":3600,"groupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","lastObservedAt":"2026-10-01T09:30:00Z","nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"observedEpoch":1,"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"promotable":true,"role":"Primary","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"observedGeneration":1,"primaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sequence":1}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"The group's committed and desired topology, its members and the aliases clients connect through."},"patch":{"tags":["Managed Services: Replication groups"],"operationId":"updateReplicationGroup","summary":"Request the next primary or mirror scope with UID and version checks.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"Current topology state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ReplicationGroup"},"example":{"apiVersion":"v1","kind":"ReplicationGroup","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{"family":"postgresql","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","primary":"primary"},"status":{"activeChange":{"epoch":1,"expiresAt":"2026-10-01T09:30:00Z","homeHub":"home-hub","intent":{"epoch":1,"groupRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"homeHub":"home-hub","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","requestedGeneration":1,"sequence":1,"source":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"strategy":"Planned","target":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}},"name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"aliases":[{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"epoch":1,"primaryUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","ready":true,"reason":"Ready","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"bootstrapPrimaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentials":{"authorityRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"caExpiresAt":"2026-10-01T09:30:00Z","profile":{"database":"app","owner":"owner","readonly":true},"revision":"9f86d081884c7d659a2feaa0c55ad015"},"epoch":1,"fences":[{"actor":"jdoe","changeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"confirmedAt":"2026-10-01T09:30:00Z","epoch":1,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","member":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"method":"RunnerAcknowledged","rebuiltNativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}],"homeHub":"home-hub","members":[{"archiveRevision":"7","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"credentialRevision":"7","credentials":{"authorityRevision":"9f86d081884c7d659a2feaa0c55ad015","expiresAt":"2026-10-01T09:30:00Z","materialRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"namespaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","projections":[{"kind":"CA","name":"web-1","sequence":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"sequence":1},"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"delaySeconds":3600,"groupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","lastObservedAt":"2026-10-01T09:30:00Z","nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"observedEpoch":1,"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"promotable":true,"role":"Primary","serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}],"observedGeneration":1,"primaryRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"sequence":1}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateReplicationGroupRequest"},"example":{"uid":"2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f","resourceVersion":"184467","primary":"orders-replica"}}}},"description":"Requests a new primary or mirror scope. The request carries the group's UID and version, so it fails if the group changed since it was read."},"delete":{"tags":["Managed Services: Replication groups"],"operationId":"deleteReplicationGroup","summary":"Delete an empty group after member, handover and fence retirement.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"202":{"description":"Current topology state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupDeletionRequested"},"example":{"status":"DeletionRequested","name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteReplicationGroupRequest"},"example":{"uid":"2c3d4e5f-6a7b-4c8d-9e0f-1a2b3c4d5e6f","resourceVersion":"184467","confirmation":"orders-replication"}}}},"description":"Deletes a group that has no members left and no handover or fence in progress."}},"/managed-services/{namespace}/replication-groups/{name}/changes":{"get":{"tags":["Managed Services: Replication groups"],"operationId":"listTopologyChanges","summary":"Handover history for this exact group incarnation.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"Current topology state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopologyChangeList"},"example":{"items":[{"apiVersion":"v1","kind":"TopologyChange","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{"epoch":1,"groupRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"homeHub":"home-hub","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","requestedGeneration":1,"sequence":1,"source":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"strategy":"Planned","target":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}},"status":{"approval":{"actor":"jdoe","approvedAt":"2026-10-01T09:30:00Z","consumersMigrated":true,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","isolationConfirmed":true,"producersQuiesced":true,"unknownLossAcknowledged":true},"committedAt":"2026-10-01T09:30:00Z","committedEpoch":1,"completedAt":"2026-10-01T09:30:00Z","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"dispatches":[{"action":"Observe","cancelConfirmed":true,"dispatchedAt":"2026-10-01T09:30:00Z","evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","memberUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","operationRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"preparedAt":"2026-10-01T09:30:00Z","terminal":true}],"evidenceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"message":"Done.","mirrorObservation":{"checkpointDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","consumerGroups":["consumer-group"],"destinationCommitsVerified":true,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","lagRecords":1,"observedAt":"2026-10-01T09:30:00Z","sourceCommitsStopped":true,"sourceProduceZero":true,"topics":["topic"]},"observations":[{"changeUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","demotionToken":"demotion-token","evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","memberUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","nativeUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","observedAt":"2026-10-01T09:30:00Z","operationUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","promotionTokenDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b","replayLSN":"replay-l-s-n","role":"Primary","systemIdentifier":"system-identifier","timeline":1}],"phase":"Preparing","reason":"Ready","validatedDemotionToken":"validated-demotion-token"}}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Primary handovers of this group incarnation, newest first."}},"/managed-services/{namespace}/replication-groups/{name}/changes/{child}":{"get":{"tags":["Managed Services: Replication groups"],"operationId":"getTopologyChange","summary":"Read the provider-owned handover record and evidence references.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"responses":{"200":{"description":"Current topology state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/TopologyChange"},"example":{"apiVersion":"v1","kind":"TopologyChange","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{"epoch":1,"groupRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"homeHub":"home-hub","mirror":{"consumerGroups":["consumer-group"],"reverseAfterCutover":true,"topics":["topic"]},"mode":"PostgresStreaming","requestedGeneration":1,"sequence":1,"source":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}},"strategy":"Planned","target":{"dataPlaneRef":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"nativeRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"placementRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"serviceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}},"status":{"approval":{"actor":"jdoe","approvedAt":"2026-10-01T09:30:00Z","consumersMigrated":true,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","isolationConfirmed":true,"producersQuiesced":true,"unknownLossAcknowledged":true},"committedAt":"2026-10-01T09:30:00Z","committedEpoch":1,"completedAt":"2026-10-01T09:30:00Z","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"dispatches":[{"action":"Observe","cancelConfirmed":true,"dispatchedAt":"2026-10-01T09:30:00Z","evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","memberUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","operationRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"preparedAt":"2026-10-01T09:30:00Z","terminal":true}],"evidenceRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"message":"Done.","mirrorObservation":{"checkpointDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","consumerGroups":["consumer-group"],"destinationCommitsVerified":true,"evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","lagRecords":1,"observedAt":"2026-10-01T09:30:00Z","sourceCommitsStopped":true,"sourceProduceZero":true,"topics":["topic"]},"observations":[{"changeUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","demotionToken":"demotion-token","evidenceDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","memberUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","nativeUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","observedAt":"2026-10-01T09:30:00Z","operationUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","promotionTokenDigest":"sha256:9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b","replayLSN":"replay-l-s-n","role":"Primary","systemIdentifier":"system-identifier","timeline":1}],"phase":"Preparing","reason":"Ready","validatedDemotionToken":"validated-demotion-token"}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"One handover record, with references to the evidence the provider recorded."}},"/managed-services/{namespace}/catalog":{"get":{"tags":["Managed Services: Catalog"],"operationId":"getCatalog","summary":"Published classes and plans, with the caller's permissions.","description":"Only verified, published plans are listed. Provider internals (storage\nprovisioners, gateway coordinates, object-store credentials) are never\nincluded. `permissions` are hints from access reviews of the caller;\nKubernetes still decides every write.\n","parameters":[{"$ref":"#/components/parameters/Namespace"}],"responses":{"200":{"description":"The catalog.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Catalog"},"example":{"contractVersion":"v1","classes":[{"name":"clickhouse","family":"clickhouse","description":"ClickHouse 25.8 LTS on the Altinity operator, with its own Keeper","revision":"2","ready":true,"parameterSchema":{"$id":"https://services.kube-dc.com/blueprints/clickhouse/0.2.0/parameters.schema.json","$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"database":{"description":"Application database created at provisioning; it is the only database the archive covers. Create-only. Default app.","pattern":"^[a-z][a-z0-9_]{0,62}$","type":"string"},"limits":{"additionalProperties":false,"description":"Per-query resource limits written as the user profiles. They bound one query, not the instance: memory and storage are what the plan sizes. They can be changed on a running service. The memory ceiling is not among them and cannot be raised from a session.","properties":{"max_concurrent_queries_for_user":{"pattern":"^[0-9]{1,4}$","type":"string"},"max_execution_time":{"description":"Seconds a single query may run before it is cancelled.","pattern":"^[0-9]{1,5}$","type":"string"},"max_result_rows":{"pattern":"^[0-9]{1,12}$","type":"string"},"max_threads":{"pattern":"^[0-9]{1,3}$","type":"string"}},"type":"object"}},"title":"ClickHouse managed service parameters","type":"object"},"uiContractVersion":"v1","mutationClasses":{"compute.cpu":"OperationOnly","compute.memory":"OperationOnly","database":"CreateOnly","engineVersion":"ReplaceOrMigrate","limits":"OnlineDesired","storage.class":"CreateOnly","storage.size":"OperationOnly","topology.replicasPerShard":"CreateOnly","topology.shards":"CreateOnly"},"tunables":[{"disruptive":true,"path":"compute.cpu","type":"quantity"},{"disruptive":true,"path":"compute.memory","type":"quantity"}],"credentialRoles":["owner","readonly"],"credentialInputs":[],"endpointRoles":[{"cardinality":"One","name":"read-write","protocol":"clickhouse","required":true,"role":"read-write"}],"capabilities":["onDemandBackup","scheduledBackup"],"operations":[{"type":"Backup","description":"Capture a native backup of the application database, package it as one object, upload it to the Project object store and verify it by reading it back.","destructive":false,"concurrencyClass":"backup","parameterSchema":{"additionalProperties":false,"properties":{},"type":"object"}},{"type":"RotateCredentials","description":"Replace the application passwords and refuse the previous ones.","destructive":false,"concurrencyClass":"credentials","parameterSchema":{"additionalProperties":false,"properties":{"role":{"enum":["owner","readonly"],"minLength":1,"title":"Credential role","type":"string"}},"required":["role"],"type":"object"}}]},{"name":"github-runner","family":"github-runner","description":"Ephemeral GitHub Actions runners for a private repository","revision":"5","ready":true,"parameterSchema":{"$schema":"https://json-schema.org/draft/2020-12/schema","additionalProperties":false,"properties":{"buildMode":{"default":"rootless-buildkit","description":"New pools build Dockerfiles with a per-job rootless BuildKit sidecar and docker buildx build by default. Choose none for shell-only jobs. Docker daemon commands, Compose and service containers are not included.","enum":["none","rootless-buildkit"],"type":"string"},"workerImage":{"description":"Optional public ghcr.io or docker.io runner image by digest. Must implement the documented non-root ARC runner image contract.","maxLength":512,"pattern":"^(ghcr\\.io|docker\\.io)/[a-z0-9][a-z0-9/._-]*@sha256:[a-f0-9]{64}$","type":"string"}},"type":"object"},"uiContractVersion":"v1","mutationClasses":{"buildMode":"CreateOnly","workerImage":"CreateOnly"},"tunables":[{"disruptive":true,"path":"compute.cpu","type":"quantity"},{"disruptive":true,"path":"compute.memory","type":"quantity"}],"credentialRoles":[],"credentialInputs":[{"keys":["github_token"],"purpose":"github-auth","required":true}],"endpointRoles":[],"capabilities":["stateless","endpointless"],"operations":[]}],"plans":[{"name":"clickhouse-development","className":"clickhouse","revision":"5","description":"One ClickHouse server with its own Keeper, for development and small analytics.","commercialTier":"development","published":true,"ready":true,"engineVersion":"25.8.2","capacity":{"cpu":"500m","memory":"2Gi","storage":"10Gi","maxStorage":"50Gi","storageRole":"database","allowedStorageClasses":[],"computeBounds":{"minCPU":"500m","maxCPU":"4","minMemory":"2Gi","maxMemory":"16Gi"}},"topology":{"ha":false},"tunables":[{"bounds":{"max":"4","min":"500m"},"disruptive":true,"path":"compute.cpu","type":"quantity"},{"bounds":{"max":"16Gi","min":"2Gi"},"disruptive":true,"path":"compute.memory","type":"quantity"}],"declarativeChanges":false,"minIsolation":"NamespaceSharedNodes","placementModes":["ProviderShared"],"connectivityClasses":["tenant-native"],"deletionPolicies":["Retain","Delete"],"allowedImages":["docker.io/clickhouse/clickhouse-server:25.8.2@sha256:74c213b4d4cb4854c2497694df0c2d153c041003eadbb0457ae62c28cb8d723f"],"support":{"tier":"T2","responsibilityText":"TLS, application and read-only credentials, scheduled verified archives and restore into a new service. One server without failover; node maintenance interrupts service. Backups cover the application database only; anything you create in another database is not archived and is deleted with the service. Replication applies to tables you declare with a Replicated engine, not to every table. Compute …"},"credentials":{"allowExistingUsers":false,"allowManagedSecretDelivery":false,"allowDatabaseEngine":false,"allowDynamicDatabaseCredentials":false},"backup":{"credentialDelivery":"Secret","enabled":true,"schedule":"0 2 * * *","retentionDays":7,"pitr":false,"minRetentionDays":1,"maxRetentionDays":35,"minScheduleIntervalMinutes":60,"customStores":false,"allowedCustomEndpoints":[]},"exposure":{"allowPublicLoadBalancer":false,"gatewayAvailable":false},"maintenance":{"day":"Sun","startHour":2,"durationMinutes":120},"maxInstancesPerProject":5,"operations":[{"type":"Backup","description":"Capture a native backup of the application database, package it as one object, upload it to the Project object store and verify it by reading it back.","destructive":false,"concurrencyClass":"backup","parameterSchema":{"additionalProperties":false,"properties":{},"type":"object"},"requiresApproval":false},{"type":"RotateCredentials","description":"Replace the application passwords and refuse the previous ones.","destructive":false,"concurrencyClass":"credentials","parameterSchema":{"additionalProperties":false,"properties":{"role":{"enum":["owner","readonly"],"minLength":1,"title":"Credential role","type":"string"}},"required":["role"],"type":"object"},"requiresApproval":false}]},{"name":"clickhouse-production","className":"clickhouse","revision":"6","description":"Two replicas of one shard with a three-member Keeper quorum.","commercialTier":"production","published":true,"ready":true,"engineVersion":"25.8.2","capacity":{"cpu":"1","memory":"4Gi","storage":"20Gi","maxStorage":"150Gi","storageRole":"database","allowedStorageClasses":[],"computeBounds":{"minCPU":"1","maxCPU":"8","minMemory":"4Gi","maxMemory":"32Gi"}},"topology":{"ha":true},"tunables":[{"bounds":{"max":"8","min":"1"},"disruptive":true,"path":"compute.cpu","type":"quantity"},{"bounds":{"max":"32Gi","min":"4Gi"},"disruptive":true,"path":"compute.memory","type":"quantity"}],"declarativeChanges":false,"minIsolation":"NamespaceSharedNodes","placementModes":["ProviderShared"],"connectivityClasses":["tenant-native"],"deletionPolicies":["Retain","Delete"],"allowedImages":["docker.io/clickhouse/clickhouse-server:25.8.2@sha256:74c213b4d4cb4854c2497694df0c2d153c041003eadbb0457ae62c28cb8d723f"],"support":{"tier":"T2","responsibilityText":"TLS, application and read-only credentials, scheduled verified archives and restore into a new service. Two replicas of one shard behind one address, coordinated by a three-member Keeper quorum that survives losing one member, each on a distinct node; a lost Keeper leaves replicated tables readable and refusing writes until it returns. Backups cover the application database only; anything you crea…"},"credentials":{"allowExistingUsers":false,"allowManagedSecretDelivery":false,"allowDatabaseEngine":false,"allowDynamicDatabaseCredentials":false},"backup":{"credentialDelivery":"Secret","enabled":true,"schedule":"0 2 * * *","retentionDays":14,"pitr":false,"minRetentionDays":7,"maxRetentionDays":35,"minScheduleIntervalMinutes":60,"customStores":false,"allowedCustomEndpoints":[]},"exposure":{"allowPublicLoadBalancer":false,"gatewayAvailable":false},"maintenance":{"day":"Sun","startHour":2,"durationMinutes":120},"maxInstancesPerProject":3,"operations":[{"type":"Backup","description":"Capture a native backup of the application database, package it as one object, upload it to the Project object store and verify it by reading it back.","destructive":false,"concurrencyClass":"backup","parameterSchema":{"additionalProperties":false,"properties":{},"type":"object"},"requiresApproval":false},{"type":"RotateCredentials","description":"Replace the application passwords and refuse the previous ones.","destructive":false,"concurrencyClass":"credentials","parameterSchema":{"additionalProperties":false,"properties":{"role":{"enum":["owner","readonly"],"minLength":1,"title":"Credential role","type":"string"}},"required":["role"],"type":"object"},"requiresApproval":false}]}],"unavailableOffers":[],"connectivityClasses":[{"name":"tenant-native","description":"Service and PVC inside the tenant's own project VPC on the Kube-DC cluster. Workloads in the project reach the ClusterIP Services directly; no public address is allocated.","reachability":"TenantNative","direction":"TenantInitiated","isolation":"TenantClusterNetwork","protocols":["TCP","TLS"],"tls":"Passthrough","endpointCardinality":"FixedN"}],"permissions":{"create":true,"configure":true,"delete":true,"operate":true,"bind":true,"editPolicies":true,"deletePolicies":true,"managePolicies":true,"readBackups":true,"createGrant":true}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/data-planes":{"get":{"tags":["Managed Services: Data planes"],"operationId":"listDataPlanes","summary":"The Project's clusters as managed-services data planes.","description":"One item per KdcCluster of the Project (remote placement): its opt-in\nannotations, the ServiceDataPlaneGrants naming it, the registration of\nthe data plane the hub generated for its live incarnation, the plane's\nfitness conditions and an eligibility verdict.\n\nKdcClusters and grants are read with the caller's token. Data planes are\nread with the backend account and shown only when sourced by this\nProject's namespace, the cluster's name and its live UID. Fitness and\nregistration carry the hub's condition types, reasons, phases and\ntimestamps only, never a message: messages can carry text from the\ntenant's own cluster.\n\n`eligibility` mirrors the hub's registration rules and the plane's\n`AcceptingPlacements` condition so the console can say why a cluster\ncannot take a service yet; the hub decides at placement.\n`families` lists the service families of published plans this Project\nsees that allow `TenantCluster`; a grant may name only these.\n`served` is false for a kind this installation does not serve.\n`permissions` are access-review hints; Kubernetes decides every write.\n","parameters":[{"$ref":"#/components/parameters/Namespace"}],"responses":{"200":{"description":"The Project's clusters.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataPlaneList"},"example":{"families":["postgresql"],"served":{"kdcClusters":true,"grants":true,"dataPlanes":true},"permissions":{"createGrant":true,"deleteGrant":true,"patchCluster":true},"items":[{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","phase":"Running","deleting":true,"clusterAPI":true,"optIn":{"enabled":true,"value":"value","families":["postgresql"]},"grant":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","clusterUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","currentIncarnation":true,"families":["postgresql"],"disclosure":"ProjectCredentialsToClusterAdministrators","phase":"Pending","reason":"DuplicateGrant","generation":1,"dataPlane":"data-plane","deleting":true,"createdAt":"2026-10-01T09:30:00Z"},"grants":[{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","clusterUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","currentIncarnation":true,"families":["postgresql"],"disclosure":"ProjectCredentialsToClusterAdministrators","phase":"Pending","reason":"DuplicateGrant","generation":1,"dataPlane":"data-plane","deleting":true,"createdAt":"2026-10-01T09:30:00Z"}],"registration":{"dataPlane":"data-plane","phase":"Bootstrapping","reason":"Ready","generation":1,"grantUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","grantWatermark":"grant-watermark","revocationDeadline":"revocation-deadline","revocationCause":"AnnotationRemoved","deleting":true,"ready":true,"families":["postgresql"]},"fitness":[{"type":"Ready","status":"True","reason":"Ready"}],"eligibility":{"eligible":true,"reason":"Ready"}}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/data-planes/{name}/grant":{"post":{"tags":["Managed Services: Data planes"],"operationId":"createDataPlaneGrant","summary":"Grant a Project cluster to run managed services.","description":"One action of a Project admin (remote placement). It creates the\nServiceDataPlaneGrant `{name}` naming the cluster's live UID, the\nfamilies and the disclosure, then sets the cluster's opt-in\nannotations `services.kube-dc.com/data-plane: enabled` and\n`services.kube-dc.com/families` (families already annotated are kept,\nthe granted ones are added). The grant comes first, so the hub never\nsees an opted-in cluster nobody granted.\n\n`acknowledgeDisclosure: true` is required: credentials of services\nplaced on the cluster, and the Project's backup bucket key, become\nreadable by the cluster's administrators. `families` may name only\nfamilies of published plans this Project sees that allow\n`TenantCluster` (409 `FamilyNotOffered`).\n\nBoth writes use the caller's token; a Project admin role is needed\n(create on servicedataplanegrants, patch on the KdcCluster), checked by\naccess review first (403) and by Kubernetes on each write. The\nannotation patch is pinned to the cluster UID and resourceVersion and\nretried only on an optimistic-lock conflict.\n\nRetry-safe without a second eligible grant: every grant naming the\ncluster's live UID is considered, whatever its name, as the hub's\nregistrar would see it once the opt-in carries the requested families.\nThe grant serving the plane's registration (Bootstrapping, Active or\nSuspended), else the unique grant the registrar could still register\nwith (never bound, created after the plane's grant watermark, covering\nan annotated family and, while Revoking, every plane family; its status\nphase is not consulted), is this request's grant when its families and\ndisclosure match (200, `created: false`), and the opt-in is completed\nif it is missing. Other families or several such grants are 409\n`GrantConflict` (grants are immutable). Obsolete grants (consumed\nhistory, an earlier incarnation, watermarked) do not count, but one\nnamed `{name}` must be deleted before the new grant can take the name:\n409 `ReplacementGrantRequired` (409 `GrantDeleting` while it is\ndeleting; 409 `GrantConflict` if it names another cluster). After a\nrevocation the bound grant can no longer reinstate: delete it, then\ngrant again.\n\nThe cluster is read again after the grant is resolved, on every path:\nif it was recreated meanwhile the answer is 409\n`ClusterIdentityChanged` and no opt-in is written. If the opt-in fails\nafter the grant was created, the grant is kept and the same request\nfinishes it.\n\n`POST /{namespace}/data-planes/{name}/grant/check` answers which of\nthese the request would get (reuse, create or a refusal) without\nwriting.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/DataPlaneClusterName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDataPlaneGrantRequest"},"example":{"families":["postgresql"],"acknowledgeDisclosure":true}}}},"responses":{"200":{"description":"The grant already existed for this request; the cluster is opted in.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataPlaneGrantResult"},"example":{"created":true,"grant":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","clusterUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","currentIncarnation":true,"families":["postgresql"],"disclosure":"ProjectCredentialsToClusterAdministrators","phase":"Pending","reason":"DuplicateGrant","generation":1,"dataPlane":"data-plane","deleting":true,"createdAt":"2026-10-01T09:30:00Z"},"optIn":{"enabled":true,"value":"value","families":["postgresql"]}}}}},"201":{"description":"The grant was created and the cluster opted in.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataPlaneGrantResult"},"example":{"created":true,"grant":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","clusterUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","currentIncarnation":true,"families":["postgresql"],"disclosure":"ProjectCredentialsToClusterAdministrators","phase":"Pending","reason":"DuplicateGrant","generation":1,"dataPlane":"data-plane","deleting":true,"createdAt":"2026-10-01T09:30:00Z"},"optIn":{"enabled":true,"value":"value","families":["postgresql"]}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}},"delete":{"tags":["Managed Services: Data planes"],"operationId":"deleteDataPlaneGrant","summary":"Withdraw a cluster grant.","description":"Deletes the grant of cluster `{name}` whose `uid` the caller reviewed\n(any grant name; 409 `GrantIdentityChanged` when no grant of this\ncluster has that uid), with a Kubernetes UID precondition and the\ncaller's token. `confirm` must be the cluster name.\n\nDeleting the grant starts the hub's revocation grace (72 hours by\ndefault; the plane's `registration.revocationDeadline`): new\nplacements stop, existing instances keep running and backing up, and a\nnew grant before the deadline reinstates the same registration. After\nthe deadline the plane retires and its instances are retained in the\ncluster. The opt-in annotation is left in place; removing it is the\nother way to opt out and also starts the grace.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/DataPlaneClusterName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteDataPlaneGrantRequest"},"example":{"uid":"1b2c3d4e-5f6a-4b7c-8d9e-0f1a2b3c4d5e","confirm":"db"}}}},"responses":{"202":{"description":"Deletion accepted. `grant` is the grant while a finalizer holds it, else null.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["grant"],"properties":{"grant":{"anyOf":[{"$ref":"#/components/schemas/DataPlaneGrant"},{"type":"null"}]}}},"example":{"grant":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","clusterUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","currentIncarnation":true,"families":["postgresql"],"disclosure":"ProjectCredentialsToClusterAdministrators","phase":"Pending","reason":"DuplicateGrant","generation":1,"dataPlane":"data-plane","deleting":true,"createdAt":"2026-10-01T09:30:00Z"}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/data-planes/{name}/grant/check":{"post":{"tags":["Managed Services: Data planes"],"operationId":"checkDataPlaneGrant","summary":"Check what a grant request would do, without writing.","description":"A dry run of `POST /{namespace}/data-planes/{name}/grant` with the same\nbody: the same validation (400), the same access reviews (403: the\nProject admin role, create on servicedataplanegrants and patch on the\nKdcCluster) and the same decision code, but nothing is created,\npatched or audited.\n\n`decision` is the grant POST's answer for these families now:\n- `reuse`: the existing grant `grantName`/`grantUID` (`grant`) would be\n  this request's grant (200 `created: false`).\n- `create`: a new grant named `{name}` would be created (201).\n- `refuse`: the POST would answer 409 with `reason`\n  (`FamilyNotOffered`, `ClusterDeleting`, `GrantConflict`,\n  `GrantDeleting` or `ReplacementGrantRequired`); `message` is the\n  POST's message.\n\nFor `reuse` and `create`, `optIn` is the cluster's opt-in now and\n`optInAnnotations` the annotations the POST would set (null when the\ncluster is already opted in for these families).\n\nThe answer is a snapshot: grants, the cluster and its data plane can\nchange before the POST, which decides again. A missing cluster (404)\nand upstream failures are errors, as on the POST; writes the POST makes\nlater can still fail (`ClusterIdentityChanged`, `OptInBusy`).\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/DataPlaneClusterName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateDataPlaneGrantRequest"},"example":{"families":["postgresql"],"acknowledgeDisclosure":true}}}},"responses":{"200":{"description":"The decision the grant POST would make now.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DataPlaneGrantCheck"},"example":{"decision":"reuse","families":["postgresql"],"grantName":"web-1","grantUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","grant":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","clusterUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","currentIncarnation":true,"families":["postgresql"],"disclosure":"ProjectCredentialsToClusterAdministrators","phase":"Pending","reason":"DuplicateGrant","generation":1,"dataPlane":"data-plane","deleting":true,"createdAt":"2026-10-01T09:30:00Z"},"optIn":{"enabled":true,"value":"value","families":["postgresql"]},"optInAnnotations":{"services.kube-dc.com/data-plane":"enabled","services.kube-dc.com/families":"services.kube-dc.com/families"}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/credential-policies":{"get":{"tags":["Managed Services: Credential policies"],"operationId":"listProjectCredentialPolicies","summary":"Every credential policy in the Project.","description":"Not pinned to an instance: the list can include policies of deleted or\nearlier incarnations. Match `spec.serviceUID` with a live instance before\noffering any instance-scoped action.\n","parameters":[{"$ref":"#/components/parameters/Namespace"}],"responses":{"200":{"description":"The policies.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialPolicyList"},"example":{"items":[{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z"},"spec":{"serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","role":"developer","existingUser":{"username":"jdoe","database":"app"},"rotationIntervalSeconds":3600,"paused":true},"status":{"credentialRole":"credential-role","observedGeneration":1,"sequence":1,"activeOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastAttemptAt":"2026-10-01T09:30:00Z","lastRotationAt":"2026-10-01T09:30:00Z","nextRotationAt":"2026-10-01T09:30:00Z","conditions":[{"type":"Ready","status":"Ready","reason":"Ready","message":"Done.","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z"}]}}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/instances":{"get":{"tags":["Managed Services: Instances"],"operationId":"listInstances","summary":"Service instances in the Project.","parameters":[{"$ref":"#/components/parameters/Namespace"}],"responses":{"200":{"description":"The instances, each with its presentation state.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceList"},"example":{"items":[{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{"lastBackup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}},"recentBackups":[{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}]},"console":{"phase":"Running","stale":true,"pendingGeneration":true,"frozen":true,"ready":true,"observedAt":"2026-10-01T09:30:00Z"},"providerOwned":true}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"The project's service instances with their plan, state and readiness."},"post":{"tags":["Managed Services: Instances"],"operationId":"createInstance","summary":"Create a service instance from a published plan.","parameters":[{"$ref":"#/components/parameters/Namespace"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateInstanceRequest"},"example":{"name":"orders","idempotencyKey":"4e5f6a7b-8c9d-4e0f-9a1b-2c3d4e5f6a7b","spec":{"classRef":{"name":"postgresql"},"planRef":{"name":"postgresql-production"},"engineVersion":"16","compute":{"cpu":"2","memory":"4Gi"},"storage":{"size":"50Gi"},"topology":{"instances":2},"maintenance":{"window":{"day":"Sun","startHour":2,"durationMinutes":120}},"deletionProtection":true}}}}},"responses":{"200":{"description":"A replay of a request that already created this instance.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedService"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{"lastBackup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}},"recentBackups":[{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}]}}}}},"201":{"description":"Created.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedService"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{"lastBackup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}},"recentBackups":[{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}]}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Creates a service instance from a published catalog plan; the price is quoted first where billing applies. Provisioning runs asynchronously; follow the returned operation."}},"/managed-services/{namespace}/instances/{name}":{"get":{"tags":["Managed Services: Instances"],"operationId":"getInstance","summary":"One instance with its class, plan and presentation state.","description":"`class` and `plan` come from the instance's own class and plan, even when\nthe catalog no longer publishes them. When they cannot be read, both are\nnull and `catalogError` explains; the instance is still returned.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"The instance.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceDetail"},"example":{"instance":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{"lastBackup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}},"recentBackups":[{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}]}},"class":{"name":"web-1","family":"postgresql","description":"Acme web shop","revision":"revision","ready":true,"parameterSchema":{},"uiContractVersion":"1","mutationClasses":{},"tunables":[{"path":"images/","type":"string","disruptive":true,"values":["value"],"bounds":{"web-1":"bounds"},"description":"Acme web shop"}],"credentialRoles":["credential-role"],"credentialInputs":[{"purpose":"purpose","keys":["images/logo.png"],"required":true}],"endpointRoles":[{}],"capabilities":["capability"],"operations":[{"type":"Ready","description":"Acme web shop","destructive":true,"concurrencyClass":"concurrency-class","parameterSchema":{}}]},"plan":{"name":"web-1","className":"web-1","revision":"revision","description":"Acme web shop","published":true,"ready":true,"engineVersion":"16","commercialTier":"commercial_tier","capacity":{"cpu":"2","memory":"4Gi","storage":"20Gi","maxStorage":"max-storage","storageClass":"local-path","storageRole":"storage-role","storageAllocationMode":"Volume","sizeMeaning":"volume","filesystemLimitEnforced":true,"allowedStorageClasses":["allowed-storage-classe"],"computeBounds":{"minCPU":"min-c-p-u","maxCPU":"max-c-p-u","minMemory":"min-memory","maxMemory":"max-memory"}},"topology":{"minInstances":2,"maxInstances":2,"defaultInstances":2,"minDataReplicas":2,"maxDataReplicas":2,"defaultDataReplicas":2,"minShards":1,"maxShards":1,"defaultShards":1,"minReplicasPerShard":1,"maxReplicasPerShard":1,"defaultReplicasPerShard":1,"ha":true,"synchronousStandbys":1,"durability":"preferred"},"tunables":[{"path":"images/","type":"string","disruptive":true,"values":["value"],"bounds":{"web-1":"bounds"},"description":"Acme web shop"}],"declarativeChanges":true,"minIsolation":"min-isolation","placementModes":["placement-mode"],"connectivityClasses":["connectivity-classe"],"deletionPolicies":["deletion-policy"],"allowedImages":["allowed-image"],"support":{"tier":"tier","responsibilityText":"responsibility-text"},"credentials":{"allowExistingUsers":true,"allowManagedSecretDelivery":true,"allowDatabaseEngine":true,"allowDynamicDatabaseCredentials":true},"backup":{"enabled":true,"schedule":"0 2 * * *","credentialDelivery":"Secret","retentionDays":1,"pitr":true,"minRetentionDays":1,"maxRetentionDays":1,"minScheduleIntervalMinutes":1,"customStores":true,"allowedCustomEndpoints":["https://web.acme-web.kube-dc.example"]},"exposure":{"allowPublicLoadBalancer":true,"gatewayAvailable":true},"maintenance":{"day":"Any","startHour":1,"durationMinutes":30},"maxInstancesPerProject":1,"operations":[{"type":"Ready","description":"Acme web shop","destructive":true,"concurrencyClass":"concurrency-class","parameterSchema":{},"requiresApproval":true}],"replication":{"mode":"PostgresStreaming","maxMembers":2,"allowCrossSite":true,"allowEmergencyFailover":true}},"console":{"phase":"Running","stale":true,"pendingGeneration":true,"frozen":true,"ready":true,"observedAt":"2026-10-01T09:30:00Z"},"providerOwned":true,"placement":{"mode":"TenantCluster","cluster":"cluster","dataPlane":"data-plane","registration":{"dataPlane":"data-plane","phase":"Bootstrapping","reason":"Ready","generation":1,"grantUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","grantWatermark":"grant-watermark","revocationDeadline":"revocation-deadline","revocationCause":"AnnotationRemoved","deleting":true,"ready":true,"families":["postgresql"]},"registrationUnavailable":true,"conditions":[{"type":"Ready","status":"True","reason":"Ready"}]},"catalogError":{"reason":"Ready","message":"Done."}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}},"patch":{"tags":["Managed Services: Instances"],"operationId":"updateInstance","summary":"Update typed configuration, engine parameters or deletion settings.","description":"Typed `compute`, `storage`, `topology` and `maintenance` objects are partial\nedits: omitted sibling fields retain their current values. For example,\n`storage: {size: 3Gi}` preserves the selected storage class. All edits are\natomic and require matching instance UID and resourceVersion.\n`parameters` replaces the whole parameter object atomically: a key missing\nfrom the request is removed.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateInstanceRequest"},"example":{"uid":"6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d","resourceVersion":"184502","compute":{"cpu":"4","memory":"8Gi"}}}}},"responses":{"200":{"description":"Updated.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedService"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{"lastBackup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}},"recentBackups":[{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}]}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}},"delete":{"tags":["Managed Services: Instances"],"operationId":"deleteInstance","summary":"Delete an instance after typed confirmation.","description":"A `Delete` deletion policy also records the confirmation on the instance\nbefore deletion. The UID and spec generation must still match the\nreviewed instance; status-only resourceVersion changes are retried.\nExisting v1 clients may send resourceVersion instead of generation;\nthat version must match at the first read.\nWhile finalizers run, the live instance is returned.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteInstanceRequest"},"example":{"uid":"6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d","generation":3,"confirmation":"orders"}}}},"responses":{"202":{"description":"Deletion accepted.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/ManagedService"},{"$ref":"#/components/schemas/Status"}]},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{"lastBackup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}},"recentBackups":[{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}]}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/instances/{name}/events":{"get":{"tags":["Managed Services: Instances"],"operationId":"listInstanceEvents","summary":"Project events of the current instance incarnation.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"The events.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectList"},"example":{"items":[{}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Kubernetes events about the instance's current incarnation, newest first."}},"/managed-services/{namespace}/instances/{name}/metrics":{"get":{"tags":["Managed Services: Instances"],"operationId":"getInstanceMetrics","summary":"Measured health of the current instance incarnation.","description":"Range series for the console health tiles, read from the platform\nPrometheus and scoped to the instance namespace and the workload the\nengine operator names after the instance. A series without samples is\nempty, never zero: a hibernated engine, a remote data plane or an\nengine without an exporter reports nothing. `capacity` is the matching\nlimit where one exists (volume capacity, `max_connections`). Series are\nadditive: clients render the keys they know and ignore the rest.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"name":"range","in":"query","required":false,"description":"Window ending now. Defaults to 24h.","schema":{"type":"string","enum":["30m","2h","24h","3d","7d"]}}],"responses":{"200":{"description":"The measured series.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/InstanceMetrics"},"example":{"range":"30m","step":1,"start":"2026-10-01T09:30:00Z","end":"2026-10-01T09:30:00Z","scope":"local","series":[{"key":"images/logo.png","label":"Web","unit":"percent","latest":1,"capacity":1,"points":[[1,1]],"available":true}]}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/instances/{name}/operations":{"get":{"tags":["Managed Services: Operations"],"operationId":"listOperations","summary":"Operations of the current instance incarnation.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"The operations.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectList"},"example":{"items":[{}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Operations (create, scale, upgrade, restore and so on) of the instance's current incarnation."},"post":{"tags":["Managed Services: Operations"],"operationId":"createOperation","summary":"Submit a day-2 operation.","description":"Poll the returned operation by name (`GET .../operations/{child}`) until a\nterminal phase. RestoreToNew uses the separate Project `POST /{namespace}/restores`\nendpoint and typed `restore` request.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateOperationRequest"},"example":{"uid":"6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d","resourceVersion":"184502","type":"Backup","idempotencyKey":"8c9d0e1f-2a3b-4c4d-9e5f-6a7b8c9d0e1f","execution":{"window":"Immediate"}}}}},"responses":{"200":{"description":"A retry of an operation that already exists.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"202":{"description":"Submitted.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/instances/{name}/operations/{child}":{"get":{"tags":["Managed Services: Operations"],"operationId":"getOperation","summary":"One operation of this instance.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"responses":{"200":{"description":"The operation.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"One operation of the instance, with its progress and result."}},"/managed-services/{namespace}/instances/{name}/operations/{child}/cancel":{"post":{"tags":["Managed Services: Operations"],"operationId":"cancelOperation","summary":"Cancel a queued operation.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedRequest"},"example":{"uid":"0e1f2a3b-4c5d-4e6f-8a7b-8c9d0e1f2a3b","resourceVersion":"184533"}}}},"responses":{"202":{"description":"Cancellation requested; the controller rechecks execution.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Cancels an operation that has not started yet. A running operation cannot be cancelled."}},"/managed-services/{namespace}/instances/{name}/bindings":{"get":{"tags":["Managed Services: Bindings"],"operationId":"listBindings","summary":"Bindings of the current instance incarnation.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"The bindings.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectList"},"example":{"items":[{}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Credentials delivered from the instance to Secrets in the project."},"post":{"tags":["Managed Services: Bindings"],"operationId":"createBinding","summary":"Deliver credentials for a role to a Secret in this Project.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateBindingRequest"},"example":{"uid":"6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d","name":"orders-app","role":"owner","deliveryMode":"DataPlaneLocalSecret","secretName":"orders-app-credentials","idempotencyKey":"2a3b4c5d-6e7f-4a8b-9c0d-1e2f3a4b5c6d"}}}},"responses":{"200":{"description":"A replay of a request that already created this binding.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"201":{"description":"Created.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Creates credentials for one of the instance's roles and writes them to a Secret in the project, for an application to mount."}},"/managed-services/{namespace}/instances/{name}/bindings/{child}":{"get":{"tags":["Managed Services: Bindings"],"operationId":"getBinding","summary":"One binding of this instance. It never carries Secret data.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"responses":{"200":{"description":"The binding.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"One binding's state and target Secret. It never returns the credentials themselves."},"delete":{"tags":["Managed Services: Bindings"],"operationId":"deleteBinding","summary":"Remove the binding; database-engine bindings also retire generated users and leases asynchronously.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedRequest"},"example":{"uid":"4c5d6e7f-8a9b-4c0d-8e1f-2a3b4c5d6e7f","resourceVersion":"184560"}}}},"responses":{"202":{"description":"Deletion accepted.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/KubernetesObject"},{"$ref":"#/components/schemas/Status"}]},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Removes the binding and its Secret. For database engines, the generated users and leases are retired asynchronously."}},"/managed-services/{namespace}/instances/{name}/bindings/{child}/reveal":{"post":{"tags":["Managed Services: Bindings"],"operationId":"revealBinding","summary":"Read the delivered credential (audited).","description":"Returns Secret values only after identity and readiness checks and a\nSecret read with the caller's token. Never cache the response.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedRequest"},"example":{"uid":"4c5d6e7f-8a9b-4c0d-8e1f-2a3b4c5d6e7f","resourceVersion":"184560"}}}},"responses":{"200":{"description":"The credential.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RevealResponse"},"example":{"secretName":"web-tls","namespace":"acme-web","encoding":"base64","data":{"API_URL":"data"}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/instances/{name}/credential-policies":{"get":{"tags":["Managed Services: Credential policies"],"operationId":"listCredentialPolicies","summary":"Credential policies of the current instance incarnation.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"The policies.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialPolicyList"},"example":{"items":[{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z"},"spec":{"serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","role":"developer","existingUser":{"username":"jdoe","database":"app"},"rotationIntervalSeconds":3600,"paused":true},"status":{"credentialRole":"credential-role","observedGeneration":1,"sequence":1,"activeOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastAttemptAt":"2026-10-01T09:30:00Z","lastRotationAt":"2026-10-01T09:30:00Z","nextRotationAt":"2026-10-01T09:30:00Z","conditions":[{"type":"Ready","status":"Ready","reason":"Ready","message":"Done.","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z"}]}}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Rotation policies of the instance's credentials."},"post":{"tags":["Managed Services: Credential policies"],"operationId":"createCredentialPolicy","summary":"Schedule rotation for a declared role or one existing SQL user.","description":"A policy schedules rotation only: it never creates a SQL login, grants\nprivileges or holds a value. It needs no ready catalog; its status reports\nentitlement and role availability.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateCredentialPolicyRequest"},"example":{"uid":"6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d","resourceVersion":"184502","name":"reporting","existingUser":{"username":"reporting","database":"orders"},"rotationIntervalSeconds":2592000}}}},"responses":{"200":{"description":"A replay of a request that already created this policy.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialPolicy"},"example":{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z"},"spec":{"serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","role":"developer","existingUser":{"username":"jdoe","database":"app"},"rotationIntervalSeconds":3600,"paused":true},"status":{"credentialRole":"credential-role","observedGeneration":1,"sequence":1,"activeOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastAttemptAt":"2026-10-01T09:30:00Z","lastRotationAt":"2026-10-01T09:30:00Z","nextRotationAt":"2026-10-01T09:30:00Z","conditions":[{"type":"Ready","status":"Ready","reason":"Ready","message":"Done.","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z"}]}}}}},"201":{"description":"Created.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialPolicy"},"example":{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z"},"spec":{"serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","role":"developer","existingUser":{"username":"jdoe","database":"app"},"rotationIntervalSeconds":3600,"paused":true},"status":{"credentialRole":"credential-role","observedGeneration":1,"sequence":1,"activeOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastAttemptAt":"2026-10-01T09:30:00Z","lastRotationAt":"2026-10-01T09:30:00Z","nextRotationAt":"2026-10-01T09:30:00Z","conditions":[{"type":"Ready","status":"Ready","reason":"Ready","message":"Done.","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z"}]}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/instances/{name}/credential-policies/{child}":{"get":{"tags":["Managed Services: Credential policies"],"operationId":"getCredentialPolicy","summary":"One credential policy of this instance.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"responses":{"200":{"description":"The policy.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialPolicy"},"example":{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z"},"spec":{"serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","role":"developer","existingUser":{"username":"jdoe","database":"app"},"rotationIntervalSeconds":3600,"paused":true},"status":{"credentialRole":"credential-role","observedGeneration":1,"sequence":1,"activeOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastAttemptAt":"2026-10-01T09:30:00Z","lastRotationAt":"2026-10-01T09:30:00Z","nextRotationAt":"2026-10-01T09:30:00Z","conditions":[{"type":"Ready","status":"Ready","reason":"Ready","message":"Done.","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z"}]}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"One rotation policy with its schedule and last rotation."},"patch":{"tags":["Managed Services: Credential policies"],"operationId":"updateCredentialPolicy","summary":"Change the interval or pause state. The target is immutable.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpdateCredentialPolicyRequest"},"example":{"uid":"6e7f8a9b-0c1d-4e2f-9a3b-4c5d6e7f8a9b","resourceVersion":"184601","rotationIntervalSeconds":604800}}}},"responses":{"200":{"description":"Updated.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CredentialPolicy"},"example":{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z"},"spec":{"serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","role":"developer","existingUser":{"username":"jdoe","database":"app"},"rotationIntervalSeconds":3600,"paused":true},"status":{"credentialRole":"credential-role","observedGeneration":1,"sequence":1,"activeOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastAttemptAt":"2026-10-01T09:30:00Z","lastRotationAt":"2026-10-01T09:30:00Z","nextRotationAt":"2026-10-01T09:30:00Z","conditions":[{"type":"Ready","status":"Ready","reason":"Ready","message":"Done.","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z"}]}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Changes a policy's rotation interval or pauses it. Which credentials it rotates cannot change."},"delete":{"tags":["Managed Services: Credential policies"],"operationId":"deleteCredentialPolicy","summary":"Stop scheduling rotation. Bindings, SQL logins and source Secrets stay.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedRequest"},"example":{"uid":"6e7f8a9b-0c1d-4e2f-9a3b-4c5d6e7f8a9b","resourceVersion":"184601"}}}},"responses":{"202":{"description":"Deletion accepted.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"anyOf":[{"$ref":"#/components/schemas/CredentialPolicy"},{"$ref":"#/components/schemas/Status"}]},"example":{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z"},"spec":{"serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","role":"developer","existingUser":{"username":"jdoe","database":"app"},"rotationIntervalSeconds":3600,"paused":true},"status":{"credentialRole":"credential-role","observedGeneration":1,"sequence":1,"activeOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastOperation":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"lastAttemptAt":"2026-10-01T09:30:00Z","lastRotationAt":"2026-10-01T09:30:00Z","nextRotationAt":"2026-10-01T09:30:00Z","conditions":[{"type":"Ready","status":"Ready","reason":"Ready","message":"Done.","observedGeneration":1,"lastTransitionTime":"2026-10-01T09:30:00Z"}]}}}}},"400":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"InvalidRequest","message":"The request has unknown fields or a field of the wrong shape."}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"403":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Stops scheduled rotation. Existing bindings, SQL logins and source Secrets stay as they are."}},"/managed-services/{namespace}/instances/{name}/backups":{"get":{"tags":["Managed Services: Backups"],"operationId":"listBackups","summary":"Backup history of the current instance incarnation.","description":"Completed means the backup completed at its recorded time, not that its\narchive is still retained. Restore additionally requires `status.recovery` with unexpired retention;\nthe hub verifies the selected record again before access. Object-store locations and credential references are\nnever returned. `sourcePlacement` says where the source ran (see BackupSourcePlacement); it is\nomitted when unknown.\n","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"}],"responses":{"200":{"description":"The backup records.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupRecordList"},"example":{"items":[{"metadata":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z"},"spec":{"origin":"origin","className":"web-1","planName":"Dev Pool","backupName":"web-1","serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"status":{"observedAt":"2026-10-01T09:30:00Z","recordedAt":"2026-10-01T09:30:00Z","recovery":{"family":"postgresql","format":"format","retainUntil":"2026-10-01T09:30:00Z"},"backup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}},"sourcePlacement":{"mode":"TenantCluster","clusterRef":{"name":"web-1"}}}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"413":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"CollectionTooLarge","message":"The collection exceeds 10,000 items."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}}}},"/managed-services/{namespace}/instances/{name}/backups/{child}":{"get":{"tags":["Managed Services: Backups"],"operationId":"getBackup","summary":"One backup record of this instance.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"responses":{"200":{"description":"The backup record.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupRecord"},"example":{"metadata":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z"},"spec":{"origin":"origin","className":"web-1","planName":"Dev Pool","backupName":"web-1","serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"status":{"observedAt":"2026-10-01T09:30:00Z","recordedAt":"2026-10-01T09:30:00Z","recovery":{"family":"postgresql","format":"format","retainUntil":"2026-10-01T09:30:00Z"},"backup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}},"sourcePlacement":{"mode":"TenantCluster","clusterRef":{"name":"web-1"}}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"404":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"NotFound","message":"Not found."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"One backup of the instance, with its state and whether it can still be restored."}},"/managed-services/{namespace}/instances/{name}/bindings/{child}/leases":{"post":{"tags":["Managed Services: Bindings"],"operationId":"issueDatabaseLease","summary":"Explicitly issue one dynamic SQL credential lease. Each successful call issues a new lease.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedRequest"},"example":{"uid":"4c5d6e7f-8a9b-4c0d-8e1f-2a3b4c5d6e7f","resourceVersion":"184560"}}}},"responses":{"201":{"description":"Lease operation completed.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseLeaseIssued"},"example":{"leaseId":"database/creds/app/k3XyZ9","leaseDurationSeconds":3600,"renewable":true,"credentials":{"username":"jdoe","password":"<password>","host":"web.acme-web.kube-dc.example","port":"443","database":"app","uri":"uri","ca.crt":"ca.crt"}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Issues one short-lived SQL user for the binding's role. Each successful call creates a new lease."}},"/managed-services/{namespace}/instances/{name}/bindings/{child}/leases/renew":{"post":{"tags":["Managed Services: Bindings"],"operationId":"renewDatabaseLease","summary":"Renew a dynamic lease of this exact binding role.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseLeaseRenewRequest"},"example":{"uid":"4c5d6e7f-8a9b-4c0d-8e1f-2a3b4c5d6e7f","resourceVersion":"184560","leaseId":"database/creds/orders-app/k3XyZ9","incrementSeconds":3600}}}},"responses":{"200":{"description":"Lease operation completed.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseLease"},"example":{"leaseId":"database/creds/app/k3XyZ9","leaseDurationSeconds":3600,"renewable":true}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Extends a dynamic SQL lease of this binding's role."}},"/managed-services/{namespace}/instances/{name}/bindings/{child}/leases/revoke":{"post":{"tags":["Managed Services: Bindings"],"operationId":"revokeDatabaseLease","summary":"Revoke a dynamic lease of this exact binding role.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Name"},{"$ref":"#/components/parameters/Child"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseLeaseRevokeRequest"},"example":{"uid":"4c5d6e7f-8a9b-4c0d-8e1f-2a3b4c5d6e7f","resourceVersion":"184560","leaseId":"database/creds/orders-app/k3XyZ9"}}}},"responses":{"204":{"description":"Lease operation completed.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"409":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"ResourceVersionChanged","message":"The object changed since it was read."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Revokes a dynamic SQL lease of this binding's role; its user stops working."}},"/managed-services/{namespace}/backups":{"get":{"tags":["Managed Services: Backups"],"operationId":"listProjectBackups","summary":"Backup history including deleted source services.","parameters":[{"$ref":"#/components/parameters/Namespace"}],"responses":{"200":{"description":"The requested resource or operation.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupRecordList"},"example":{"items":[{"metadata":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z"},"spec":{"origin":"origin","className":"web-1","planName":"Dev Pool","backupName":"web-1","serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"status":{"observedAt":"2026-10-01T09:30:00Z","recordedAt":"2026-10-01T09:30:00Z","recovery":{"family":"postgresql","format":"format","retainUntil":"2026-10-01T09:30:00Z"},"backup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}},"sourcePlacement":{"mode":"TenantCluster","clusterRef":{"name":"web-1"}}}]}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Every backup in the project, including those of services that have since been deleted, for restore into a new service."}},"/managed-services/{namespace}/backups/{child}":{"get":{"tags":["Managed Services: Backups"],"operationId":"getProjectBackup","summary":"One Project catalog backup incarnation.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Child"}],"responses":{"200":{"description":"The requested resource or operation.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupRecord"},"example":{"metadata":{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z"},"spec":{"origin":"origin","className":"web-1","planName":"Dev Pool","backupName":"web-1","serviceRef":{"name":"web-1"},"serviceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"status":{"observedAt":"2026-10-01T09:30:00Z","recordedAt":"2026-10-01T09:30:00Z","recovery":{"family":"postgresql","format":"format","retainUntil":"2026-10-01T09:30:00Z"},"backup":{"family":"postgresql","format":"format","artifact":{"sha256":"9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08","bytes":1,"payloadBytes":1},"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","sourceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","phase":"Running","startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","engineMajor":"engine-major","method":"method","message":"Done.","archivingHealthy":true,"firstRecoverabilityPoint":"first-recoverability-point","lastArchivedWALTime":"2026-10-01T09:30:00Z","lastSuccessfulBackupTime":"2026-10-01T09:30:00Z","recoveryWindow":{"earliest":"earliest","latest":"latest","backupID":"backup-i-d","backupUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timeline":1,"engineMajor":"engine-major","verifiedAt":"2026-10-01T09:30:00Z"}}},"sourcePlacement":{"mode":"TenantCluster","clusterRef":{"name":"web-1"}}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"One backup from the project's backup history."}},"/managed-services/{namespace}/operations/{child}":{"get":{"tags":["Managed Services: Operations"],"operationId":"getProjectOperation","summary":"Poll an operation independently of its source service.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Child"}],"responses":{"200":{"description":"The requested resource or operation.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"description":"Polls an operation by name, even after its service was deleted."}},"/managed-services/{namespace}/operations/{child}/cancel":{"post":{"tags":["Managed Services: Operations"],"operationId":"cancelProjectOperation","summary":"Request cancellation before execution is claimed.","parameters":[{"$ref":"#/components/parameters/Namespace"},{"$ref":"#/components/parameters/Child"}],"responses":{"202":{"description":"The requested resource or operation.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PinnedRequest"},"example":{"uid":"8a9b0c1d-2e3f-4a4b-8c5d-6e7f8a9b0c1d","resourceVersion":"184622"}}}},"description":"Requests cancellation of an operation that no worker has picked up yet."}},"/managed-services/{namespace}/restores":{"post":{"tags":["Managed Services: Operations"],"operationId":"createRestore","summary":"Restore a retained catalog backup into a new service.","parameters":[{"$ref":"#/components/parameters/Namespace"}],"responses":{"200":{"description":"The requested resource or operation.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"202":{"description":"The requested resource or operation.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesObject"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"}},"spec":{},"status":{}}}}},"401":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Unauthorized","message":"No bearer token was supplied."}}}},"default":{"description":"An error. `reason` is listed in `x-reasons`, or passed through from Kubernetes.","headers":{"Cache-Control":{"$ref":"#/components/headers/CacheControl"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"reason":"Forbidden","message":"Your role does not allow this."}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreateRestoreRequest"},"example":{"serviceRef":{"name":"orders"},"serviceUID":"6a7b8c9d-0e1f-4a2b-8c3d-4e5f6a7b8c9d","idempotencyKey":"0c1d2e3f-4a5b-4c6d-9e7f-8a9b0c1d2e3f","restore":{"backupRef":{"name":"orders-20261002-0200","uid":"1d2e3f4a-5b6c-4d7e-8f9a-0b1c2d3e4f5a"},"targetTime":"2026-10-02T14:30:00Z","target":{"name":"orders-restored","planRef":{"name":"postgresql-production"},"engineVersion":"16.4","placement":{"mode":"ProviderShared"},"connectivity":{"classRef":{"name":"internal"}}}},"execution":{"window":"Immediate"}}}}},"description":"Select an exact ServiceBackup name/UID and explicitly describe the target. Source identity is historical; a live source service or its plan is not required. Cancellation is available until the hub commits status.restore before the first target CREATE. Target deletionPolicy is Retain when supported by the target plan, otherwise Delete. RabbitMQ restores queue, exchange and binding definitions only on the original plan; queued messages are excluded. The target plan controls approval and the requested maintenance window. The hub verifies the retained archive, source and target identities again before transfer."}},"/billing/managed-quote":{"post":{"tags":["Billing: Quotes"],"operationId":"quoteManagedService","summary":"Price a shape of a published managed-service plan for the caller's organization.","description":"The organization comes from the caller's verified token. The body\nnames a plan and a shape; the billing service reads the plan, its\nclass, the storage class and the rate card the organization's own\nbilling policy names, so nothing in the request sets a price, a UID\nor a member count the plan does not allow.\n\nA quote that cannot be made is an answer, not an error: 200 with\n`quotable: false`, a `reason` and a `message`, and no total. A\npriced quote is stored immutably under `quoteId` for 24 hours so an\norder can cite it. Amounts are stated for 730 hours. When the card's\nprices start later, `pricesEffectiveFrom` is the first date at which\nthis shape is priced and the window starts there. `collectionMode:\nshadow` means the figure is an estimate and nothing is charged.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedQuoteRequest"},"example":{"operation":"create","plan":"postgresql-production","cpu":"2","memory":"4Gi","storage":"50Gi","members":2}}}},"responses":{"200":{"description":"A priced quote, or the reason there is none.","content":{"application/json":{"schema":{"type":"object","required":["status","data"],"properties":{"status":{"const":"success"},"data":{"$ref":"#/components/schemas/ManagedQuote"}}},"example":{"status":"success","data":{"quotable":true,"reason":"not_payg","message":"Done.","quoteId":"q-0123456789abcdef0123456789abcdef","createdAt":"2026-10-01T09:30:00Z","expiresAt":"2026-10-01T09:30:00Z","basis":"730h","pricesEffectiveFrom":"2026-10-01T09:30:00Z","collectionMode":"shadow","policyRevision":"7","request":{"operation":"create","plan":"plan","cpu":"2","memory":"4Gi","storage":"20Gi","storageClass":"local-path","members":2,"shards":1,"replicasPerShard":1,"dataReplicas":2},"result":{"rateCard":"rate-card","planUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","planRevision":"7","currency":"EUR","scope":"scope","from":"2026-10-01T09:30:00Z","to":"2026-10-01T09:30:00Z","members":2,"storageClassUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","storageQualificationRevision":1,"lines":[{"sku":"compute.cpu","unitPrice":"1","priceUnit":"price-unit","baseQuantity":"1","amount":"1"}],"subtotal":"1"},"omitted":[{"component":"component","note":""}]}}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"404":{"description":"PAYG is not enabled on this installation; the route does not exist."},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/billing/managed-quote/{quoteId}":{"parameters":[{"name":"quoteId","in":"path","required":true,"schema":{"type":"string","pattern":"^q-[0-9a-f]{32}$"}}],"get":{"tags":["Billing: Quotes"],"operationId":"getManagedServiceQuote","summary":"Read back one of the caller organization's quotes, exactly as issued.","description":"Quotes are keyed by the live organization's UID; another\norganization's quote id is 404. An expired quote is still returned,\nwith its `expiresAt`, so the customer can see what was offered.\n","responses":{"200":{"description":"The stored quote.","content":{"application/json":{"schema":{"type":"object","required":["status","data"],"properties":{"status":{"const":"success"},"data":{"$ref":"#/components/schemas/ManagedQuote"}}},"example":{"status":"success","data":{"quotable":true,"reason":"not_payg","message":"Done.","quoteId":"q-0123456789abcdef0123456789abcdef","createdAt":"2026-10-01T09:30:00Z","expiresAt":"2026-10-01T09:30:00Z","basis":"730h","pricesEffectiveFrom":"2026-10-01T09:30:00Z","collectionMode":"shadow","policyRevision":"7","request":{"operation":"create","plan":"plan","cpu":"2","memory":"4Gi","storage":"20Gi","storageClass":"local-path","members":2,"shards":1,"replicasPerShard":1,"dataReplicas":2},"result":{"rateCard":"rate-card","planUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","planRevision":"7","currency":"EUR","scope":"scope","from":"2026-10-01T09:30:00Z","to":"2026-10-01T09:30:00Z","members":2,"storageClassUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","storageQualificationRevision":1,"lines":[{"sku":"compute.cpu","unitPrice":"1","priceUnit":"price-unit","baseQuantity":"1","amount":"1"}],"subtotal":"1"},"omitted":[{"component":"component","note":""}]}}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/organizations/{organization}/costs":{"parameters":[{"$ref":"#/components/parameters/Organization"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/GroupBy"},{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Limit"}],"get":{"tags":["Billing: Reports"],"operationId":"getOrganizationCosts","summary":"Grouped usage and estimated cost.","description":"Bounded window, allowlisted grouping, bounded pages. Filters are\nsupplied as query parameters whose names are allowlisted dimension keys;\nthere is no caller-supplied SQL, column name or JSONPath.\n\n`pricedSubtotal` is what is known. `estimatedTotal` is null whenever any\nexpected component is missing or unpriced, and the `coverage` array says\nwhich and why. A zero amount appears only for a confirmed zero\nmeasurement or an explicitly included component.\n\nAuthorization is the caller's own: the bearer token must be able to read\nthe Organization through the Kubernetes API (403 otherwise, before any\nusage is read). Filters narrow the lines, never the rating: the whole\norganization is rated -- allowances are shared by all its groups -- and\na filtered key is added to the grouping. `pricedSubtotal` and\n`estimatedTotal` are for the whole (filtered) report, not the page.\nA range starting inside an allowance month is rated with the month's\nearlier usage, and its `coverage` then starts at the month start.\nUsage rating-v1 cannot allocate exactly (an allowance that changes\nwithin its month, coarse usage straddling a boundary in an allowance\nmonth) is refused with 422 `UNSUPPORTED` rather than approximated.\n`nextCursor` is bound to the organization, the query and the report\nthat produced it: if the report has changed since the first page\n(usage arriving for the range), a continuation answers 409\n`REVISION_CONFLICT` -- request it again from the start -- rather than\npage a shifted list. Usage and coverage are read separately; when the\nevents rated are not the events coverage counted, `estimatedTotal` is\nnull and `coverageNote` says so. Without the billing service the route\nanswers 503.\n","responses":{"200":{"description":"The report.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostReport"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","organization":"acme","organizationUid":"3f2504e0-4f89-41d3-9a0c-000000000011","from":"2026-10-02T00:57:00Z","to":"2026-10-03T00:57:00Z","groupBy":[],"collectionMode":"shadow","billable":false,"usageSource":"billing.usage_records+unbilled","lines":[{"dimensions":{},"sku":"","meter":"container_cpu_request_seconds","quantity":"0","unit":"vcpu_second","normalizedQuantity":null,"includedQuantity":null,"chargedQuantity":null,"unitPrice":null,"amount":null,"pricingStatus":"not_configured","quality":"observed","chargeComponent":"","usageCategory":"","policyRevision":"0","calculationVersion":"rating-v1","eventCount":5,"distinctResources":5},{"dimensions":{},"sku":"","meter":"container_memory_request_byte_seconds","quantity":"0","unit":"byte_second","normalizedQuantity":null,"includedQuantity":null,"chargedQuantity":null,"unitPrice":null,"amount":null,"pricingStatus":"not_configured","quality":"observed","chargeComponent":"","usageCategory":"","policyRevision":"0","calculationVersion":"rating-v1","eventCount":5,"distinctResources":5}],"coverage":[{"meter":"accelerator_allocation_seconds_v1","source":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","state":"missing","expectedIntervals":0,"observedIntervals":0,"gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-02T00:57:00Z","windowEnd":"2026-10-03T00:56:00Z","meters":["accelerator_allocation_seconds_v1"],"reason":"not_assessed","detectedAt":"2026-10-03T00:56:00Z"}],"qualification":"draft","pricingStatus":"not_configured","note":"1439 window(s) could not be assessed; collector observations; no rate card is in force for this organization"},{"meter":"container_cpu_request_seconds","source":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","state":"partial","expectedIntervals":5,"observedIntervals":5,"watermark":"2026-10-03T00:48:00Z","gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-02T04:57:00Z","windowEnd":"2026-10-02T04:58:00Z","meters":["container_cpu_request_seconds"],"reason":"not_derived","detectedAt":"2026-10-02T04:58:00Z"},{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-02T10:29:00Z","windowEnd":"2026-10-02T10:30:00Z","meters":["container_cpu_request_seconds"],"reason":"not_derived","detectedAt":"2026-10-02T10:30:00Z"}],"qualification":"draft","pricingStatus":"not_configured","note":"95 window(s) could not be assessed; collector observations; no rate card is in force for this organization"}],"pricedSubtotal":null,"estimatedTotal":null,"hasMore":false,"coverageNote":"Estimates from shadow metering; not an invoice."}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"409":{"description":"Revision mismatch, reused idempotency key with a different body, an edit\nto immutable data, a UID mismatch, a commerce-owner conflict, an active\nhold, or an outstanding provider handoff.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Revision mismatch, reused idempotency key with a different body, an edit to immutable data, a UID mismatch, a commerce-owner conflict, an active hold, or an outstanding provider handoff.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/organizations/{organization}/coverage":{"parameters":[{"$ref":"#/components/parameters/Organization"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"}],"get":{"tags":["Billing: Reports"],"operationId":"getOrganizationCoverage","summary":"What is actually measured, and how completely.","description":"Per product and per source: expected versus observed intervals, open\ngaps, watermarks, qualification and whether a price exists. A component\nwith no collector is `unsupported`, which is different from `missing`.\n\nIntervals are component-intervals: one project (v1 meters) or one\nresource (v2 meters) for one minute. A component is expected in a\nminute when it exists at both ends of it. An organization with no\ncomponent in the range is `complete` with nothing expected; that is not\nzero usage of something that existed. `from`/`to` are whole minutes,\nat most 31 days apart, `to` not in the future (400 otherwise).\n","responses":{"200":{"description":"The coverage report.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CoverageReport"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","organization":"acme","organizationUid":"3f2504e0-4f89-41d3-9a0c-000000000011","from":"2026-10-02T00:57:00Z","to":"2026-10-03T00:57:00Z","entries":[{"meter":"accelerator_allocation_seconds_v1","source":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","state":"missing","expectedIntervals":0,"observedIntervals":0,"gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-02T00:57:00Z","windowEnd":"2026-10-03T00:56:00Z","meters":["accelerator_allocation_seconds_v1"],"reason":"not_assessed","detectedAt":"2026-10-03T00:56:00Z"}],"qualification":"draft","pricingStatus":"not_configured","note":"1439 window(s) could not be assessed; collector observations; no rate card is in force for this organization"},{"meter":"container_cpu_request_seconds","source":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","state":"partial","expectedIntervals":5,"observedIntervals":5,"watermark":"2026-10-03T00:48:00Z","gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-02T04:57:00Z","windowEnd":"2026-10-02T04:58:00Z","meters":["container_cpu_request_seconds"],"reason":"not_derived","detectedAt":"2026-10-02T04:58:00Z"},{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-02T10:29:00Z","windowEnd":"2026-10-02T10:30:00Z","meters":["container_cpu_request_seconds"],"reason":"not_derived","detectedAt":"2026-10-02T10:30:00Z"}],"qualification":"draft","pricingStatus":"not_configured","note":"95 window(s) could not be assessed; collector observations; no rate card is in force for this organization"}],"sources":[{"source":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","lastAcceptedSequence":"724","lastEventTime":"2026-10-03T00:48:00Z","lagSeconds":46,"openGaps":530,"state":"partial"},{"source":"fees.managed-services","openGaps":0,"state":"missing"}]}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/organizations/{organization}/costs/export":{"parameters":[{"$ref":"#/components/parameters/Organization"},{"$ref":"#/components/parameters/From"},{"$ref":"#/components/parameters/To"},{"$ref":"#/components/parameters/GroupBy"},{"$ref":"#/components/parameters/Cursor"}],"get":{"tags":["Billing: Reports"],"operationId":"exportOrganizationCosts","summary":"Paginated evidence export.","description":"The same report, from the same calculation, with the same authorization\nand allowlists, in pages of 1000 lines (no `limit`). CSV is chosen by\n`format=csv` or an `Accept: text/csv` header; JSON is the default. A\nCSV page is the lines only -- one row per line, the grouping keys first\n-- with the report figures in headers: `X-Priced-Subtotal`,\n`X-Estimated-Total` (empty when null), `X-Currency`, `X-Has-More`,\n`X-Next-Cursor`. Every CSV cell is quoted; a cell whose first\nsignificant character (after whitespace, control characters or a BOM)\nis `=`, `+`, `-` or `@`, or that opens with a tab or CR, is prefixed\nwith an apostrophe: a tenant-controlled value in a downloaded report is\notherwise a formula-injection vector. Served `nosniff`, never cached.\nEvent-level evidence is the `events` report.\n","parameters":[{"name":"format","in":"query","required":false,"schema":{"type":"string","enum":["csv","json"]},"description":"File format of the export."}],"responses":{"200":{"description":"One page of evidence.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CostReport"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","organization":"acme","organizationUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","from":"2026-10-01T09:30:00Z","to":"2026-10-01T09:30:00Z","groupBy":["group-by"],"currency":"EUR","mode":"quota_only","collectionMode":"shadow","billable":true,"usageSource":"metering.resource_usage_events+metering.usage_events","lines":[{"dimensions":{"web-1":"dimensions"},"sku":"compute.cpu","meter":"cpu_core_seconds","quantity":"1","unit":"unit","normalizedQuantity":"1","priceUnit":"price-unit","includedQuantity":"1","chargedQuantity":"1","unitPrice":"1","amount":"1","currency":"EUR","pricingStatus":"priced","quality":"observed","chargeComponent":"charge-component","usageCategory":"usage-category","policyRevision":"7","rateRevision":"7","calculationVersion":"1","scale":1,"eventCount":2,"distinctResources":1}],"coverage":[{"sku":"compute.cpu","meter":"cpu_core_seconds","source":"source","state":"complete","expectedIntervals":1,"observedIntervals":1,"watermark":"2026-10-01T09:30:00Z","gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"cell.zrh.postgresql","epoch":"epoch","fromSequence":"from-sequence","toSequence":"to-sequence","windowStart":"2026-10-01T09:30:00Z","windowEnd":"2026-10-01T09:30:00Z","meters":["cpu_core_seconds"],"reason":"Ready","detectedAt":"2026-10-01T09:30:00Z","repairedAt":"2026-10-01T09:30:00Z"}],"moreGaps":true,"qualification":"draft","pricingStatus":"priced","note":""}],"pricedSubtotal":"1","estimatedTotal":"1","nextCursor":"next-cursor","hasMore":true,"coverageNote":"coverage-note"}},"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"409":{"description":"Revision mismatch, reused idempotency key with a different body, an edit\nto immutable data, a UID mismatch, a commerce-owner conflict, an active\nhold, or an outstanding provider handoff.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Revision mismatch, reused idempotency key with a different body, an edit to immutable data, a UID mismatch, a commerce-owner conflict, an active hold, or an outstanding provider handoff.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/organizations/{organization}/budget":{"parameters":[{"$ref":"#/components/parameters/Organization"}],"get":{"tags":["Billing: Budgets"],"operationId":"getOrganizationBudget","summary":"The advisory monthly budget and where the month stands.","description":"ADVISORY: a budget is the organization's own monthly spending reference\nand the thresholds it wants to hear about. It never holds, suspends or\nlimits anything; credit enforcement reads its own inputs.\n\nThe month is the current UTC calendar month up to the current minute,\nrated exactly as `costs` rates it. `spend` is the month's established\ntotal when there is one (`spendBasis: total`), otherwise only its priced\nsubtotal (`priced_subtotal`), which is a LOWER BOUND: `usedPercent` is\nthen \"at least\", and `remaining` is null -- a lower bound cannot say\nwhat is left. Percentages are rounded down to two places. With nothing priced, `spendBasis` is `none`. A spend in\nanother currency than the budget's is not compared. `alerts` are the\nthresholds reached this month, each raised once with the figure it was\nraised on. `budget` is null when none is set.\n\nReading needs read access to the Organization (the caller's own token,\nthrough the Kubernetes API). Without the billing service: 503.\n","responses":{"200":{"description":"The budget status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetStatus"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","organization":"acme","organizationUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","period":"2026-10-01T09:30:00Z","asOf":"2026-10-01T09:30:00Z","budget":{"contractVersion":"payg.kube-dc.com/v1alpha1","amount":"1","currency":"EUR","thresholds":[1],"version":1,"updatedAt":"2026-10-01T09:30:00Z","updatedBy":"jdoe"},"spend":"1","spendBasis":"total","usageSource":"metering.resource_usage_events+metering.usage_events","currency":"EUR","usedPercent":"1","remaining":"1","alerts":[{"period":"2026-10-01T09:30:00Z","threshold":1,"spend":"1","currency":"EUR","lowerBound":true,"budgetAmount":"1","budgetVersion":1,"raisedAt":"2026-10-01T09:30:00Z","notifiedAt":"2026-10-01T09:30:00Z"}],"note":""}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}},"put":{"tags":["Billing: Budgets"],"operationId":"putOrganizationBudget","summary":"Create or replace the budget.","description":"Changing a budget needs UPDATE access to the Organization, decided by\nthe API server for the caller's own token (a SelfSubjectAccessReview);\nread access is not enough (403, before the body is read). The body is\nstrict: at most 16 KiB, no unknown or duplicate keys. `version` names\nthe version the writer read -- 0 to create -- and a stale one is 409\n`REVISION_CONFLICT`, never a silent overwrite. Versions increase and\nare never reused, not even by a budget deleted and created again; they\nare not consecutive. `updatedAt` and\n`updatedBy` are the server's: whatever the body says is replaced with\nthe time and the caller's own username.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Budget"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","amount":"500.00","currency":"EUR","thresholds":[50,80,100],"version":0}}}},"responses":{"200":{"description":"The budget as stored, at its new version.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Budget"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","amount":"1","currency":"EUR","thresholds":[1],"version":1,"updatedAt":"2026-10-01T09:30:00Z","updatedBy":"jdoe"}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"409":{"description":"Revision mismatch, reused idempotency key with a different body, an edit\nto immutable data, a UID mismatch, a commerce-owner conflict, an active\nhold, or an outstanding provider handoff.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Revision mismatch, reused idempotency key with a different body, an edit to immutable data, a UID mismatch, a commerce-owner conflict, an active hold, or an outstanding provider handoff.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}},"delete":{"tags":["Billing: Budgets"],"operationId":"deleteOrganizationBudget","summary":"Remove the budget.","description":"The same authorization as `put`. `version` is required and names the\nversion read (409 when it is stale). Alerts already raised are kept:\nthey record what was said.\n","parameters":[{"name":"version","in":"query","required":true,"schema":{"type":"integer","minimum":1},"description":"The budget version as last read; the delete fails if it changed."}],"responses":{"204":{"description":"Removed."},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"409":{"description":"Revision mismatch, reused idempotency key with a different body, an edit\nto immutable data, a UID mismatch, a commerce-owner conflict, an active\nhold, or an outstanding provider handoff.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Revision mismatch, reused idempotency key with a different body, an edit to immutable data, a UID mismatch, a commerce-owner conflict, an active hold, or an outstanding provider handoff.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/organizations/{organization}/forecasts":{"parameters":[{"$ref":"#/components/parameters/Organization"}],"get":{"tags":["Billing: Budgets"],"operationId":"getOrganizationForecast","summary":"An optional month-end estimate, with its method and assumptions.","description":"`run-rate-v1` projects the month to date over the whole UTC month at the\nrate observed so far. It is unavailable (`available: false`, with\n`reasons`) before a full day of the month has passed, when nothing is\npriced, or when fewer than half of the month's expected measurements\nwere observed; it is never a guess presented as a figure. Projected\nfrom a priced subtotal it is a lower bound too (`lowerBound: true`,\n`confidence: low`). The same authorization as reading the budget.\n","responses":{"200":{"description":"The forecast, available or not.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForecastReport"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","organization":"acme","organizationUid":"3f2504e0-4f89-41d3-9a0c-000000000011","period":"2026-10-01T00:00:00Z","asOf":"2026-10-03T00:57:00Z","available":false,"method":"run-rate-v1","basis":"none","lowerBound":false,"monthToDate":null,"projected":null,"assumptions":[],"reasons":["No priced usage is known for this month."],"coverage":[{"meter":"accelerator_allocation_seconds_v1","source":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","state":"missing","expectedIntervals":0,"observedIntervals":0,"gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-01T00:00:00Z","windowEnd":"2026-10-03T00:56:00Z","meters":["accelerator_allocation_seconds_v1"],"reason":"not_assessed","detectedAt":"2026-10-03T00:56:00Z"}],"qualification":"draft","pricingStatus":"not_configured","note":"2936 window(s) could not be assessed; collector observations; no rate card is in force for this organization"},{"meter":"container_cpu_request_seconds","source":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","state":"partial","expectedIntervals":5,"observedIntervals":5,"watermark":"2026-10-03T00:48:00Z","gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-01T07:07:00Z","windowEnd":"2026-10-01T07:08:00Z","meters":["container_cpu_request_seconds"],"reason":"not_derived","detectedAt":"2026-10-01T07:08:00Z"},{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"urn:kube-dc:installation:3f2504e0-4f89-41d3-9a0c-000000000012","epoch":"","windowStart":"2026-10-01T08:30:00Z","windowEnd":"2026-10-01T08:37:00Z","meters":["container_cpu_request_seconds"],"reason":"not_assessed","detectedAt":"2026-10-01T08:37:00Z"}],"qualification":"draft","pricingStatus":"not_configured","note":"122 window(s) could not be assessed; collector observations; no rate card is in force for this organization"}],"usageSource":"billing.usage_records+unbilled"}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/producers":{"get":{"tags":["Billing: Producers"],"operationId":"listProducers","summary":"The producers registered to deliver usage.","description":"Platform authority: the caller's own token must be able to CREATE\nOrganizations cluster-wide (a SelfSubjectAccessReview). Read access\nis not enough -- a read-only cluster viewer can list organizations\nand says nothing about who may bind a billing identity.\n","responses":{"200":{"description":"The registrations.","content":{"application/json":{"schema":{"type":"object","required":["contractVersion","producers"],"properties":{"contractVersion":{"const":"payg.kube-dc.com/v1alpha1"},"producers":{"type":"array","items":{"$ref":"#/components/schemas/ProducerRegistration"}}}},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","producers":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"cell.zrh.postgresql","scope":{"installationUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","dataPlaneUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","clusterUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","meters":["cpu_core_seconds"]},"epoch":"1","registeredAt":"2026-10-01T09:30:00Z","revokedAt":"2026-10-01T09:30:00Z"}]}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}},"post":{"tags":["Billing: Producers"],"operationId":"registerProducer","summary":"Register a producer, or open its next epoch.","description":"The same call is the first registration and the restart path. A\nproducer that lost its sequence state registers again and is told\nwhich epoch to deliver under; the previous epoch is closed, so a late\ndelivery under it is refused rather than misread as a gap in the new\nstream. Nothing a closed epoch accepted is removed.\n\n`subject` is the authenticated identity that may deliver as this\nproducer -- for an in-cluster producer, its Kubernetes username. One\nidentity belongs to one producer (409 otherwise). The scope given\nreplaces the scope held: what a producer may report about is the\nplatform's decision. A revoked producer is not re-registered by\nrestarting (403).\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["producerId","scope","subject"],"properties":{"producerId":{"type":"string"},"scope":{"$ref":"#/components/schemas/ProducerScope"},"subject":{"type":"string"}}},"example":{"producerId":"cell.zrh.postgresql","scope":{"installationUid":"3f2504e0-4f89-11d3-9a0c-0305e82c3301","dataPlaneUid":"dp-zrh-1","meters":["backup_base_byte_seconds"]},"subject":"system:serviceaccount:kube-dc-services:metering-producer"}}}},"responses":{"200":{"description":"The registration, with the epoch to deliver under.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProducerRegistration"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"cell.zrh.postgresql","scope":{"installationUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","dataPlaneUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","clusterUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","meters":["cpu_core_seconds"]},"epoch":"1","registeredAt":"2026-10-01T09:30:00Z","revokedAt":"2026-10-01T09:30:00Z"}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"409":{"description":"Revision mismatch, reused idempotency key with a different body, an edit\nto immutable data, a UID mismatch, a commerce-owner conflict, an active\nhold, or an outstanding provider handoff.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Revision mismatch, reused idempotency key with a different body, an edit to immutable data, a UID mismatch, a commerce-owner conflict, an active hold, or an outstanding provider handoff.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/producers/{producer}/revoke":{"post":{"tags":["Billing: Producers"],"operationId":"revokeProducer","summary":"End a producer's ability to deliver.","description":"Platform authority, as for registration. Every open epoch is closed\nand no new evidence is accepted. Everything the producer delivered is\nkept: that history is why the charges derived from it are trusted,\nand a retry of an already committed batch still receives its original\nacknowledgement. Revoking twice is not an error.\n","parameters":[{"name":"producer","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the registered usage producer."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["reason"],"properties":{"reason":{"type":"string","minLength":1}}},"example":{"reason":"Data plane dp-zrh-1 decommissioned."}}}},"responses":{"204":{"description":"Revoked."},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/producers/{producer}/batches":{"post":{"tags":["Billing: Producers"],"operationId":"deliverUsageBatch","summary":"Deliver one batch of usage.","description":"The caller is authenticated first, then must be the identity bound to\nthis registration: a registered producer cannot deliver as another,\nand platform authority does not grant delivery either. An\nunauthenticated caller reaches no journal read, so it cannot learn\nwhich producers exist. The binding is checked again inside the\ntransaction that stores the usage, so a registration rotated while a\ndelivery is in flight is decided against as it is then.\n\nDeliveries are bounded: one request at a time has a deadline, and\nbeyond a small number in flight the route answers 503 with\n`Retry-After` -- a retryable answer a producer keeps its spool for,\nnever a silent drop. An identity service that cannot answer is also\n503, not 401: a producer told its credentials are bad stops retrying.\n\n**Durable commit precedes the acknowledgement.** The usage, the\ncursor, any gap, the watermark and the batch record are one\ntransaction, and the acknowledgement is returned only after it\ncommits -- and stored, so a retry after a lost response gets back the\nsame document, even if the stream has moved on or the identity was\nrevoked since. `accepted`, `duplicate` and `conflicts` account for\nevery event in the batch.\n\nThe stream of an epoch starts at sequence 1. A batch arriving after a\nhole is stored, but `acceptedSequence` does not advance past the\nmissing sequences and the hole is recorded as a repairable gap; it is\nclosed when every sequence of it is held. A retry of a committed\nsequence under a different idempotency key, or of a key with\ndifferent content, is 409.\n\nWhat a producer asserts is evidence, never authority. Ownership is\nresolved from the platform's own effective-dated bindings at event\ntime: a claim that contradicts one refuses the batch (422), and usage\nwith no binding is stored unattributed and unbillable, with an\n`attribution_unverified` gap. The producer must deliver as its own\nsource (`<installationUid>/<producerId>`), for its registered meters,\nand -- when its registration names a data plane -- about that plane.\nTwo observations of one component window are a double count (409).\n","parameters":[{"name":"producer","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the registered usage producer."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/UsageBatch"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"cell.zrh.postgresql","epoch":"3","sequence":"128","windowStart":"2026-09-19T10:00:00Z","windowEnd":"2026-09-19T10:05:00Z","idempotencyKey":"cell.zrh.postgresql/3/128","events":[{"specversion":"1.0","id":"b1f0b0d2f1a34f6f9d1a5b6c7d8e9f001122334455667788990011223344556f","source":"inst-1/cell.zrh.postgresql","subject":"3f2504e0-4f89-11d3-9a0c-0305e82c3301","type":"com.kube-dc.payg.backup_base_byte_seconds.v1","time":"2026-09-19T10:00:00Z","datacontenttype":"application/json","data":{"meter":"backup_base_byte_seconds","quantity":"3221225472000","unit":"byte_second","window_start":"2026-09-19T10:00:00Z","window_end":"2026-09-19T10:05:00Z","quality":"observed","billable":false,"usage_category":"managed_backup","contract_version":"payg.kube-dc.com/v1alpha1","dimensions":{"project_uid":"9b2504e0-4f89-11d3-9a0c-0305e82c3302","service_family":"postgresql","service_uid":"svc-1","product_sku":"storage.backup.base","region":"zrh","compute_class":"not_applicable","storage_tier":"unknown","usage_category":"managed_backup","charge_component":"backup","data_plane_uid":"dp-zrh-1"}}}]}}}},"responses":{"200":{"description":"The acknowledgement, after the batch is durably committed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BatchAck"},"example":{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"cell.zrh.postgresql","epoch":"epoch","acceptedSequence":"1","accepted":1,"duplicate":1,"conflicts":["conflict"],"nextExpectedSequence":"1","committedAt":"2026-10-01T09:30:00Z"}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"409":{"description":"Revision mismatch, reused idempotency key with a different body, an edit\nto immutable data, a UID mismatch, a commerce-owner conflict, an active\nhold, or an outstanding provider handoff.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Revision mismatch, reused idempotency key with a different body, an edit to immutable data, a UID mismatch, a commerce-owner conflict, an active hold, or an outstanding provider handoff.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/metering/v1/producers/{producer}/gaps":{"post":{"tags":["Billing: Producers"],"operationId":"reportProducerGaps","summary":"Report windows of this producer's meters it could not measure.","description":"Authenticated first; only the identity bound to the registration may\nreport, and only for meters it is registered for, judged again inside\nthe transaction that records them. A report is a statement that\nevidence is MISSING -- it never removes or replaces evidence, and the\nproducer cannot mark its own gaps repaired. Reasons are the producer's\n(`source_unavailable`, `producer_restart`, ...); sequence holes are the\njournal's own. A gap may name the one organization whose measurement\nis missing. Each gap is recorded once, identified by its content, so a\nretry after a lost response records nothing new. At most 500 gaps per\nreport; windows may not end in the future or exceed 31 days.\n","parameters":[{"name":"producer","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the registered usage producer."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","additionalProperties":false,"required":["gaps"],"properties":{"gaps":{"type":"array","maxItems":500,"items":{"$ref":"#/components/schemas/ProducerGap"}}}},"example":{"gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"cell.zrh.postgresql","epoch":"3","windowStart":"2026-09-19T10:05:00Z","windowEnd":"2026-09-19T10:20:00Z","meters":["backup_base_byte_seconds"],"reason":"Object store unreachable; sizes were not measured.","detectedAt":"2026-09-19T10:21:04Z"}]}}}},"responses":{"200":{"description":"How many of the reported gaps were new.","content":{"application/json":{"schema":{"type":"object","required":["contractVersion","recorded","reported"],"properties":{"contractVersion":{"type":"string"},"recorded":{"type":"integer","minimum":0},"reported":{"type":"integer","minimum":0}}},"example":{"contractVersion":"1","recorded":1,"reported":1}}}},"400":{"description":"Malformed request.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Malformed request.","details":{"web-1":"details"}}}}}},"401":{"description":"Missing or invalid bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Missing or invalid bearer token.","details":{"web-1":"details"}}}}}},"403":{"description":"Authenticated but not authorized for this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Authenticated but not authorized for this organization.","details":{"web-1":"details"}}}}}},"404":{"description":"No such organization, policy, revision or transition.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"No such organization, policy, revision or transition.","details":{"web-1":"details"}}}}}},"422":{"description":"Well-formed but semantically invalid, or unsupported.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"Well-formed but semantically invalid, or unsupported.","details":{"web-1":"details"}}}}}},"503":{"description":"The journal or a required source could not be read. Never answered as a\nsuccessful empty or zero report.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorEnvelope"},"example":{"status":"error","error":{"code":"BAD_REQUEST","message":"The journal or a required source could not be read. Never answered as a successful empty or zero report.","details":{"web-1":"details"}}}}}}}}},"/volume/{namespace}/tree":{"get":{"summary":"Get volume tree structure","tags":["Volumes"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Volume tree with PVCs and attached VMs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VolumeTreeItem"}},"example":[{"id":1,"uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","name":"web-1","inner_name":"inner_name","storageClass":"local-path","type":"Ready","capacity":"20Gi","attached":"attached","attachedTo":"attached-to","startedTimestamp":"2026-10-01T09:30:00Z"}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getVolumeTree","description":"The project's volumes (PVCs) with size, storage class and the VM each is attached to, for the console's volume list."}},"/volume/{namespace}/persistentvolumes/{name}":{"get":{"summary":"Get a specific persistent volume","tags":["Volumes"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the PersistentVolume."}],"responses":{"200":{"description":"Persistent volume details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"persistentvolumes \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"persistentvolumes\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getVolumePersistentvolumesByName","description":"One PersistentVolume as stored by Kubernetes. PersistentVolumes are cluster-wide, so tenants usually get 403."}},"/volume/{namespace}/persistentvolumeclaims/{name}":{"get":{"summary":"Get a specific PVC","tags":["Volumes"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the PersistentVolumeClaim."}],"responses":{"200":{"description":"PVC details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"kind":"PersistentVolumeClaim","apiVersion":"v1","metadata":{"name":"data-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-000000000003","resourceVersion":"660490435","creationTimestamp":"2026-10-03T00:58:22Z","finalizers":["kubernetes.io/pvc-protection"]},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"1Gi"}},"storageClassName":"local-path","volumeMode":"Filesystem"},"status":{"phase":"Pending"}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"persistentvolumeclaims \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"persistentvolumeclaims\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getVolumePersistentvolumeclaimsByName","description":"One PersistentVolumeClaim as stored by Kubernetes."},"delete":{"summary":"Delete a PVC","tags":["Volumes"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the PersistentVolumeClaim."}],"responses":{"200":{"description":"PVC deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"kind":"PersistentVolumeClaim","apiVersion":"v1","metadata":{"name":"data-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-000000000003","resourceVersion":"660490441","creationTimestamp":"2026-10-03T00:58:22Z","deletionTimestamp":"2026-10-03T00:58:22Z","deletionGracePeriodSeconds":0,"finalizers":["kubernetes.io/pvc-protection"]},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"1Gi"}},"storageClassName":"local-path","volumeMode":"Filesystem"},"status":{"phase":"Pending"}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"An upstream service answered unexpectedly.","reason":"InternalError","code":502}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"persistentvolumeclaims \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"persistentvolumeclaims\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteVolumePersistentvolumeclaimsByName","description":"Deletes the PVC and, with it, the data on it. Detach it from its VM first."}},"/volume/{namespace}/persistentvolumeclaims":{"post":{"summary":"Create a PVC and attach to VM","tags":["Volumes"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"query","name":"amount","schema":{"type":"string"},"description":"Storage amount (e.g., 10Gi)"},{"in":"query","name":"name","schema":{"type":"string"},"description":"Name of the new PVC."},{"in":"query","name":"vm","schema":{"type":"string"},"description":"Virtual machine to hot-plug the new volume into."},{"in":"query","name":"class","schema":{"type":"string"},"description":"Storage class of the new volume."},{"in":"query","name":"accessMode","required":false,"description":"Access mode of the new volume.","schema":{"type":"string","enum":["ReadWriteOnce","ReadWriteMany","ReadOnlyMany"],"default":"ReadWriteOnce"}},{"in":"query","name":"volumeMode","required":false,"description":"Volume mode of the new volume.","schema":{"type":"string","enum":["Filesystem","Block"],"default":"Filesystem"}}],"responses":{"201":{"description":"PVC created and attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"kind":"PersistentVolumeClaim","apiVersion":"v1","metadata":{"name":"data-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-000000000003","resourceVersion":"660490435","creationTimestamp":"2026-10-03T00:58:22Z","finalizers":["kubernetes.io/pvc-protection"]},"spec":{"accessModes":["ReadWriteOnce"],"resources":{"requests":{"storage":"1Gi"}},"storageClassName":"local-path","volumeMode":"Filesystem"},"status":{"phase":"Pending"}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"persistentvolumeclaims \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"persistentvolumeclaims\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postVolumePersistentvolumeclaims","description":"Creates an empty PVC and hot-plugs it into a running VM. Query: `name`, `amount` (size, for example `20Gi`), `class` (storage class), `vm`, and optional `accessMode` (ReadWriteOnce by default) and `volumeMode` (Filesystem by default). Answers 201 with the new volume, or 200 with KubeVirt's answer when it was also attached to `vm`."}},"/volume/{namespace}/datavolumes":{"post":{"summary":"Create a DataVolume and attach to VM","tags":["Volumes"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"query","name":"amount","schema":{"type":"string"},"description":"Size of the new volume, for example `20Gi`."},{"in":"query","name":"name","schema":{"type":"string"},"description":"Name of the new DataVolume."},{"in":"query","name":"vm","schema":{"type":"string"},"description":"Virtual machine to hot-plug the new volume into."},{"in":"query","name":"class","schema":{"type":"string"},"description":"Storage class of the new volume."},{"in":"query","name":"accessMode","required":false,"description":"Access mode of the new volume.","schema":{"type":"string","enum":["ReadWriteOnce","ReadWriteMany","ReadOnlyMany"],"default":"ReadWriteOnce"}},{"in":"query","name":"volumeMode","required":false,"description":"Volume mode of the new volume.","schema":{"type":"string","enum":["Filesystem","Block"],"default":"Filesystem"}}],"responses":{"201":{"description":"DataVolume created and attached","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"datavolumes \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"datavolumes\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postVolumeDatavolumes","description":"Creates an empty DataVolume and hot-plugs it into a running VM. Same query as creating a PVC: `name`, `amount`, `class`, `vm`, `accessMode`, `volumeMode`. Answers 201 with the new volume, or 200 with KubeVirt's answer when it was also attached to `vm`."}},"/volume/{namespace}/persistentvolumeclaims/delete":{"post":{"summary":"Bulk delete PVCs","tags":["Volumes"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"volumeNames":{"type":"array","items":{"type":"string"}}}},"example":{"volumeNames":["data-1","data-2"]}}}},"responses":{"200":{"description":"PVCs deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postVolumePersistentvolumeclaimsDelete","description":"Deletes several volumes in one call. Body: `{ \"volumeNames\": [...] }`. The response reports each volume's result."}},"/virtual-machines/{namespace}/tree":{"get":{"summary":"Get VM and Managed Cluster tree structure","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Tree structure with VMs and Managed Clusters","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TreeNode"}},"example":[{"id":1111,"name":"acme-web","children":[{"id":2222,"name":"Virtual Machines","children":[]},{"id":3333,"name":"Managed Clusters","children":[]}]}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getVirtualMachinesTree","description":"The project's VMs and managed clusters (with their worker VMs) as a navigation tree, with each VM's status."}},"/virtual-machines/{namespace}/vmi/{name}":{"get":{"summary":"Get VM instance details","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."}],"responses":{"200":{"description":"VM instance details with metrics","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getVirtualMachinesVmiByName","description":"The running VirtualMachineInstance of a VM, with its IP addresses, node and guest agent data. 404 when the VM is not running."}},"/virtual-machines/{namespace}/vms":{"get":{"summary":"List all VMs in a Project","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of virtual machines","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/VmWithInstance"}},"example":[{"vm":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"vmi":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"Done.","reason":"Forbidden","details":{},"code":403}}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getVirtualMachinesVms","description":"Every VM in the project with its running instance. For a stopped VM, `vmi` is a Kubernetes NotFound Status."}},"/virtual-machines/{namespace}/unpause/{name}":{"post":{"summary":"Unpause a VM","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."}],"responses":{"200":{"description":"VM unpaused","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"unpause \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"unpause\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postVirtualMachinesUnpauseByName","description":"Resumes a paused VM."}},"/virtual-machines/{namespace}/pause/{name}":{"post":{"summary":"Pause a VM","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."}],"responses":{"200":{"description":"VM paused","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"pause \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"pause\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postVirtualMachinesPauseByName","description":"Freezes a running VM in memory. It keeps its resources; unpause to resume."}},"/virtual-machines/{namespace}/stop/{name}":{"post":{"summary":"Stop a VM","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."}],"responses":{"200":{"description":"VM stopped","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"stop \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"stop\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postVirtualMachinesStopByName","description":"Shuts the VM down and keeps it stopped. Disks and configuration are kept."}},"/virtual-machines/{namespace}/reboot/{name}":{"patch":{"summary":"Reboot a VM","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."}],"responses":{"200":{"description":"VM rebooted","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"reboot \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"reboot\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchVirtualMachinesRebootByName","description":"Restarts the VM. Configuration changes that need a restart (CPU, memory) apply now."}},"/virtual-machines/{namespace}/start/{name}":{"post":{"summary":"Start a VM","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."}],"responses":{"200":{"description":"VM started","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"start \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"start\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postVirtualMachinesStartByName","description":"Starts a stopped VM."}},"/virtual-machines/{namespace}/screenshot/{name}":{"get":{"summary":"PNG screenshot of a running VM's console","tags":["Virtual Machines"],"responses":{"200":{"description":"PNG image","content":{"image/png":{"schema":{"type":"string","format":"binary"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"text/plain":{"schema":{"type":"string"},"example":"An upstream service answered unexpectedly."}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"screenshot \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"screenshot\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the running virtual machine."}],"operationId":"getVirtualMachinesScreenshotByName","description":"A PNG of the VM's console screen. The VM must be running."}},"/project":{"get":{"summary":"List all projects","description":"Lists projects across all organizations, so it needs cluster-wide read access to projects; tenants get 403.","tags":["Organization"],"responses":{"200":{"description":"List of projects","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectList"},"example":{"apiVersion":"kube-dc.com/v1","kind":"ProjectList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"kube-dc.com/v1","kind":"Project","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"cidrBlock":"cidr-block","egressNetworkType":"public","gwLanIp":"10.0.10.15","network":{"loadBalancerBlocks":1}},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"namespace":"acme-web","quotaUsage":{"accelerators":{"nvidia-v100-hami":{"corePercent":{"hard":"4","used":"1"},"devices":{"hard":"4","used":"1"},"memoryMiB":{"hard":"4","used":"1"},"shares":{"hard":"4","used":"1"}}},"cpu":{"hard":"4","used":"1"},"cpuBreakdown":{"platformOverhead":"platform-overhead","workloads":"workloads"},"lastUpdated":"2026-10-01T09:30:00Z","memory":{"hard":"4","used":"1"},"perProjectQuotaSet":true,"pods":{"hard":"4","used":"1"},"storage":{"hard":"4","used":"1"},"storageAccounting":"native"},"ready":false,"security":{"certificateManager":{"count":2,"expiringSoon":1,"ready":true,"synced":1},"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"databaseCredentials":{"count":2,"expiringSoon":1,"ready":true,"synced":1},"databaseMount":"database-mount","kms":{"count":2,"expiringSoon":1,"ready":true,"synced":1},"kvMount":"kv-mount","secretStoreName":"web-1","secretsManager":{"count":2,"expiringSoon":1,"ready":true,"synced":1},"servicePublicationMount":"service-publication-mount","servicePublicationSecretStore":"service-publication-secret-store","servicePublicationServiceAccount":"service-publication-service-account","syncServiceAccount":"sync-service-account"}}}]}}}},"403":{"description":"Kubernetes Status; the caller may not list projects cluster-wide."}},"operationId":"getProject"}},"/node/{namespace}/tree":{"get":{"summary":"Get node tree with VMs","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Tree structure of nodes with their VMs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TreeNode"}},"example":[{"id":1,"name":"web-1","status":"Ready","children":[]}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getNodeTree","description":"The project's VMs grouped by the host node they run on."}},"/network/{namespace}/project-networks":{"get":{"summary":"List datacenter VLANs assigned to a Project","description":"Lists the ProjectNetwork grants that apply to one Project's backing namespace,\nso the console can show which datacenter VLANs the Project may attach\nto and the exact manifest to do it with.\n\nREAD ONLY, deliberately. An Organization admin never self-assigns a VLAN: the\ngrant is what stops another Project taking the wire, so it stays with\nthe platform admin (see the admin API under /api/admin/vlans).\n\nProjectNetwork is CLUSTER-SCOPED, which rules out letting the apiserver\ndecide on the caller's behalf: a namespaced Role cannot cover the kind\nat all, and a ClusterRole that could list it would expose every other\nOrganization's VLAN grants. Authorization is therefore a two-step process:\na SelfSubjectAccessReview under the caller's own token establishes Project\nmembership (probe: `list eips` in that backing namespace, which every\nstandard Project role carries), and only then is the cluster-wide list read\nwith the backend service account and filtered to that backing namespace.\n","tags":["Networking"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Assigned VLANs. Every binding is listed with its phase, including\nones still provisioning or draining, so a Project member can see a VLAN\narriving or going away. `attach` — the ready-to-paste pod\nannotation and KubeVirt network/interface pair — is present only on\na binding whose NAD is published, since a snippet for any other\nphase would be refused by admission.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectNetworkList"},"example":{"success":true,"enabled":true,"items":[{}]}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Not signed in, or the session expired.","code":"OK"}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Your role does not allow this.","code":"OK"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Not found.","code":"OK"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"An upstream service answered unexpectedly.","code":"OK"}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"A required service is unavailable; retry later.","code":"OK"}}}}},"operationId":"getNetworkProjectNetworks"}},"/network/{namespace}/gateway":{"get":{"summary":"Get the Project's default gateway External IP","tags":["Networking"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Default gateway External IP details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EIp"},"example":{"apiVersion":"kube-dc.com/v1","kind":"EIp","metadata":{"creationTimestamp":"2026-10-03T00:57:27Z","finalizers":["eip.kube-dc.com/finalizer"],"generation":1,"labels":{"network.kube-dc.com/external-network-type":"cloud"},"name":"default-gw","namespace":"acme-web","resourceVersion":"660488173","uid":"3f2504e0-4f89-41d3-9a0c-000000000010"},"spec":{"externalNetworkType":"cloud"},"status":{"ipAddress":"100.65.0.124","ovnEIpRef":"eip-default-gw-ede995e3990f542d","owners":[{"ownerRef":"default-gw","type":"Snat"}],"ownershipType":"Shared","ready":true}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getNetworkGateway","description":"The External IP the project's outbound traffic leaves from (its default gateway)."}},"/network/{namespace}/eips":{"get":{"summary":"List External IPs in a Project","tags":["Networking"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of External IPs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EIpList"},"example":{"apiVersion":"kube-dc.com/v1","items":[{"apiVersion":"kube-dc.com/v1","kind":"EIp","metadata":{"creationTimestamp":"2026-10-03T00:57:27Z","finalizers":["eip.kube-dc.com/finalizer"],"generation":1,"labels":{"network.kube-dc.com/external-network-type":"cloud"},"name":"default-gw","namespace":"acme-web","resourceVersion":"660488173","uid":"3f2504e0-4f89-41d3-9a0c-000000000010"},"spec":{"externalNetworkType":"cloud"},"status":{"ipAddress":"100.65.0.124","ovnEIpRef":"eip-default-gw-ede995e3990f542d","owners":[{"ownerRef":"default-gw","type":"Snat"}],"ownershipType":"Shared","ready":true}}],"kind":"EIpList","metadata":{"continue":"","resourceVersion":"660488834"}}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getNetworkEips","description":"The project's External IPs as a Kubernetes list."},"post":{"summary":"Create an External IP","tags":["Networking"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EIp"},"example":{"apiVersion":"kube-dc.com/v1","kind":"EIp","metadata":{"name":"web-ip"},"spec":{"externalNetworkType":"public"}}}}},"responses":{"201":{"description":"External IP created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EIp"},"example":{"apiVersion":"kube-dc.com/v1","kind":"EIp","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"childRef":"child-ref","externalNetworkType":"external-network-type"},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"deleteReleased":true,"ipAddress":"10.0.10.15","ovnEIpRef":"ovn-e-ip-ref","owners":[{"ownerRef":"owner-ref","type":"Ready"}],"ownershipType":"Released","ready":false}}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"eips \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"eips\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postNetworkEips","description":"Allocates an External IP for the project from an EIp manifest. Attach it with a Floating IP or a LoadBalancer Service."}},"/network/{namespace}/eips/{name}":{"get":{"summary":"Get an External IP","tags":["Networking"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the External IP."}],"responses":{"200":{"description":"External IP details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EIp"},"example":{"apiVersion":"kube-dc.com/v1","kind":"EIp","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"childRef":"child-ref","externalNetworkType":"external-network-type"},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"deleteReleased":true,"ipAddress":"10.0.10.15","ovnEIpRef":"ovn-e-ip-ref","owners":[{"ownerRef":"owner-ref","type":"Ready"}],"ownershipType":"Released","ready":false}}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"eips \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"eips\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getNetworkEipsByName","description":"One External IP with its address and owners."},"delete":{"summary":"Delete an External IP","tags":["Networking"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the External IP."}],"responses":{"200":{"description":"External IP deleted","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"eips \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"eips\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteNetworkEipsByName","description":"Releases the External IP. Floating IPs and Services using it lose their public address."}},"/network/{namespace}/fips":{"get":{"summary":"List Floating IPs in a Project","tags":["Networking"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of Floating IPs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FIpList"},"example":{"apiVersion":"kube-dc.com/v1","kind":"FIpList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"kube-dc.com/v1","kind":"FIp","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"allowedCIDRs":["10.0.10.0/24"],"eip":"web-ip","externalNetworkType":"public","ipAddress":"10.0.10.15","vmTarget":{"interfaceName":"web-1","vmName":"web-1"}},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"eip":"web-ip","externalIP":"10.0.10.15","ovnFip":"ovn-fip","ready":false,"resolvedTargetIP":"10.0.10.15","sourcePolicyRevision":"7","sourcePolicySpecHash":"source-policy-spec-hash","targetVMInterface":{"interfaceName":"web-1","ipAddress":"10.0.10.15","mac":"mac","vmName":"web-1"}}}]}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getNetworkFips","description":"The project's Floating IPs as a Kubernetes list."},"post":{"summary":"Create a Floating IP","description":"Maps an External IP to a VM or pod IP in the project.","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"requestBody":{"required":true,"description":"A `kube-dc.com/v1` FIp object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FIp"},"examples":{"vm":{"summary":"Public IP for a VM","value":{"apiVersion":"kube-dc.com/v1","kind":"FIp","metadata":{"name":"web-public"},"spec":{"externalNetworkType":"public","vmTarget":{"vmName":"web-1"}}}},"address":{"summary":"Public IP for a project address","value":{"apiVersion":"kube-dc.com/v1","kind":"FIp","metadata":{"name":"web-fip"},"spec":{"ipAddress":"10.0.10.15","externalNetworkType":"public"}}}}}}},"responses":{"201":{"description":"Created FIp.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FIp"},"example":{"apiVersion":"kube-dc.com/v1","kind":"FIp","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"allowedCIDRs":["10.0.10.0/24"],"eip":"web-ip","externalNetworkType":"public","ipAddress":"10.0.10.15","vmTarget":{"interfaceName":"web-1","vmName":"web-1"}},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"eip":"web-ip","externalIP":"10.0.10.15","ovnFip":"ovn-fip","ready":false,"resolvedTargetIP":"10.0.10.15","sourcePolicyRevision":"7","sourcePolicySpecHash":"source-policy-spec-hash","targetVMInterface":{"interfaceName":"web-1","ipAddress":"10.0.10.15","mac":"mac","vmName":"web-1"}}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"postNetworkFips"}},"/metrics/{namespace}/metrics":{"get":{"summary":"Get VM metrics over time","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"query","name":"vm_name","required":true,"schema":{"type":"string"},"description":"Virtual machine name"},{"in":"query","name":"filter","schema":{"type":"string"},"description":"Time filter (e.g., 1h, 24h, 7d)"}],"responses":{"200":{"description":"VM metrics (RAM, CPU, storage, disk I/O)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VmMetrics"},"example":{"cpu":{"status":"Ready","data":{"resultType":"result-type","result":[{}]}},"ram":{"status":"Ready","data":{"resultType":"result-type","result":[{}]}},"storage":{"status":"Ready","data":{"resultType":"result-type","result":[{}]}},"diskio":{"status":"Ready","data":{"resultType":"result-type","result":[{}]}}}}}},"400":{"description":"The namespace or vm_name is not a valid Kubernetes name.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"401":{"description":"No bearer token.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"No bearer token."}}}},"502":{"description":"Access to the virtual machine could not be checked.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Access to the virtual machine could not be checked."}}}},"default":{"description":"Reading the virtual machine with your token was refused; 403 when your role does not allow it, 404 when it does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"Reading the virtual machine with your token was refused; 403 when your role does not allow it, 404 when it does not exist.","reason":"InternalError","code":500}}}}},"operationId":"getMetricsMetrics","description":"CPU, memory, storage and disk I/O usage of one VM over time, from Prometheus. Query: `vm_name`, and `filter`: `Last 3 days`, `Last 2 hours`, `Last 30 mins`, or omitted for the last 24 hours."}},"/k8s-clusters/{namespace}/clusters":{"get":{"summary":"List Managed Clusters in a Project","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of Managed Clusters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedClusterList"},"example":{"total":2,"items":[{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","version":"v1.33.1","phase":"Running","endpoint":"https://web.acme-web.kube-dc.example","controlPlaneReplicas":2,"controlPlaneReady":true,"dataStoreName":"web-1","eipName":"web-ip","workerPools":[{"name":"web-1","replicas":2,"provider":"provider","cpuCores":1,"memory":"4Gi"}],"labels":{"app":"labels"},"createdAt":"2026-10-01T09:30:00Z"}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"clusters \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"clusters\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getK8sClustersClusters","description":"The project's managed clusters with version, phase, API endpoint and worker pools."},"post":{"summary":"Create a Managed Cluster","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedClusterCreate"},"example":{"name":"prod","version":"v1.33.4","enableClusterAPI":true,"publicApiEndpoint":true,"workers":[{"name":"general","replicas":3,"cpuCores":2,"memory":"4Gi","diskSize":"20Gi"}]}}}},"responses":{"201":{"description":"Managed Cluster creation started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterCreated"},"example":{"name":"web-1","namespace":"acme-web","message":"Done."}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"409":{"description":"Conflicts with the current state; read it again and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Conflicts with the current state; read it again and retry."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"clusters \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"clusters\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postK8sClustersClusters","description":"Creates a managed cluster from a KdcCluster spec (version, control plane, worker pools, network, endpoint mode). Provisioning takes several minutes; watch the cluster's phase."}},"/k8s-clusters/{namespace}/clusters/{name}":{"get":{"summary":"Get a Managed Cluster","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"responses":{"200":{"description":"Managed Cluster details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedCluster"},"example":{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","labels":{"app":"labels"},"annotations":{"app":"annotations"},"creationTimestamp":"2026-10-01T09:30:00Z"},"spec":{"backup":{"destinationPath":"images/","enabled":true,"retentionDays":7,"s3CredentialSecret":"web-tls","s3Endpoint":"https://web.acme-web.kube-dc.example","schedule":"0 2 * * *"},"controlPlane":{"autoscaling":{"maxAllowed":{"web-1":{"web-1":1}},"minReplicas":2,"mode":"InPlaceOrRecreate"},"replicas":2,"resources":{"apiServer":{"limits":{"web-1":1},"requests":{"web-1":1}},"controllerManager":{"limits":{"web-1":1},"requests":{"web-1":1}},"scheduler":{"limits":{"web-1":1},"requests":{"web-1":1}}}},"dataStore":{"dedicated":false,"eipName":"web-ip","name":"web-1","namespace":"acme-web","port":1024},"eip":{"create":true,"externalNetworkType":"public","name":"web-1"},"enableClusterAPI":false,"encryption":{"etcd":{"backup":{"keyRef":"key-ref"},"disableRequested":true,"enabled":false,"kekRotation":{"enabled":false,"interval":"30d"},"keyRef":"key-ref","resources":["secrets"]}},"kubelet":{"evictionHard":{"web-1":"1"},"kubeReserved":{"web-1":"1"},"maxPods":10,"systemReserved":{"web-1":"1"}},"loadBalancer":{"blocks":1},"network":{"controlPlaneEndpointMode":"External","podCIDR":"10.244.0.0/16","serviceCIDR":"10.96.0.0/12","workerMTU":576},"publicAPIAllowedCIDRs":["10.0.10.0/24"],"publicApiEndpoint":false,"version":"1","workerHealthCheck":{"enabled":true,"maxUnhealthy":1,"nodeStartupTimeoutSeconds":3600,"unhealthyTimeoutSeconds":3600},"workers":[{"architecture":"amd64","autoscaling":{"behavior":{"scaleDown":{"cooldownSeconds":3600,"enabled":true,"stabilizationWindowSeconds":3600,"utilizationThreshold":75},"scaleUp":{"cooldownSeconds":3600,"maxNodesPerStep":1,"stabilizationWindowSeconds":3600}},"enabled":true,"maxReplicas":2,"metrics":[{"targetAverageUtilization":75,"type":"cpu"}],"minReplicas":2,"mode":"Builtin"},"cloudsigma":{"ccmImage":"ccm-image","cpuMHz":1000,"diskSizeGB":1,"imageUUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","meta":{"web-1":"meta"},"mhzPerCore":1000,"nics":[{"ipPoolRef":{"apiGroup":"ipam.cluster.x-k8s.io","kind":"InClusterIPPool","name":"web-1"},"loadBalancer":true,"public":true,"vlan":"vlan"}],"privateApiEndpointIP":"10.0.10.15","region":"zrh","tags":["tag"]},"cpuCores":1,"diskSize":"10Gi","healthCheck":{"enabled":true,"maxUnhealthy":1,"nodeStartupTimeoutSeconds":3600,"unhealthyTimeoutSeconds":3600},"image":"nginx:1.27","infrastructureProvider":"kubevirt","labels":{"app":"labels"},"memory":"2Gi","name":"web-1","nodeDrainTimeoutSeconds":3600,"nodeVolumeDetachTimeoutSeconds":3600,"paused":true,"replicas":2,"storageClassName":"local-path","storageType":"datavolume","strategy":{"maxSurge":1,"maxUnavailable":1},"taints":[{"effect":"effect","key":"images/logo.png","timeAdded":"2026-10-01T09:30:00Z","value":"value"}],"version":"v1.33.4"}]},"status":{"backupBucket":"backup-bucket","backupDestinationPath":"images/","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"controlPlane":{"autoscalingMode":"autoscaling-mode","lastRecommendationUpdate":"2026-10-01T09:30:00Z","recommendations":[{"containerName":"web-1","lowerBound":{"web-1":1},"target":{"web-1":1},"uncappedTarget":{"web-1":1},"upperBound":{"web-1":1}}],"version":"1"},"controlPlaneReady":true,"dataStoreName":"web-1","eipName":"web-ip","encryption":{"currentKeyVersion":1,"disableMigrationProgress":1,"kekRotation":{"currentVersion":1,"enabled":true,"lastRotatedTime":"2026-10-01T09:30:00Z","minDecryptionVersion":1,"nextRotationTime":"2026-10-01T09:30:00Z"},"kmsPluginReady":true,"lastRewrapCompleted":"2026-10-01T09:30:00Z","resolvedBackupKeyRef":"resolved-backup-key-ref","resolvedKeyRef":"resolved-key-ref","rewrapInProgress":true},"endpoint":"https://web.acme-web.kube-dc.example","latestBackupKey":"latest-backup-key","latestBackupTime":"2026-10-01T09:30:00Z","latestRestoreKey":"latest-restore-key","latestRestoreTime":"2026-10-01T09:30:00Z","loadBalancer":{"blocks":[{"addressSpaceUID":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","delegatable":true,"enabled":true,"message":"Done.","phase":"Running","range":"range","ready":true,"reservation":"reservation","vipCIDR":"10.0.10.0/24"}],"configMap":"config-map","enabled":true,"mode":"default","revision":1},"phase":"Running","publicApiEndpoint":"https://web.acme-web.kube-dc.example","workerPools":[{"autoscaling":{"currentCPUUtilization":75,"currentMemoryUtilization":75,"lastScaleReason":"Done.","lastScaleTime":"2026-10-01T09:30:00Z","limitedBy":"limited-by","maxReplicas":2,"minReplicas":2,"mode":"default"},"blockedReplicas":2,"deletingReplicas":2,"message":"Done.","name":"web-1","observedVersion":"1","paused":true,"phase":"Running","readyReplicas":2,"reason":"Ready","replicas":2,"updatedReplicas":2,"version":"1"}],"workerRootDiskIdentity":{"web-1":"worker-root-disk-identity"}}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"clusters \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"clusters\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getK8sClustersClustersByName","description":"The cluster's spec and status, including conditions and restore state."},"delete":{"summary":"Delete a Managed Cluster","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"responses":{"200":{"description":"Managed Cluster deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterMessage"},"example":{"message":"Done."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"clusters \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"clusters\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteK8sClustersClustersByName","description":"Deletes the cluster, its control plane and worker VMs. Take a final etcd snapshot first if you may need the data."}},"/k8s-clusters/{namespace}/clusters/{name}/machinedeployments":{"get":{"summary":"Get MachineDeployments for a Managed Cluster","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"responses":{"200":{"description":"List of MachineDeployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterItems"},"example":{"items":[{}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"machinedeployments \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"machinedeployments\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getK8sClustersClustersMachinedeployments","description":"The Cluster API MachineDeployments behind the cluster's worker pools, with their replica counts."}},"/k8s-clusters/{namespace}/clusters/{name}/kubeconfig":{"get":{"summary":"Get kubeconfig for a Managed Cluster","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"responses":{"200":{"description":"Kubeconfig content","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterKubeconfig"},"example":{"kubeconfig":"kubeconfig","secretName":"web-tls"}}}},"404":{"description":"Kubeconfig not found"}},"operationId":"getK8sClustersClustersKubeconfig","description":"An admin kubeconfig for the cluster's API server, and the Secret it came from. Treat it as a secret."}},"/k8s-clusters/{namespace}/clusters/{name}/scale":{"patch":{"summary":"Scale worker pool replicas","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"workerPoolName":{"type":"string"},"replicas":{"type":"integer"}}},"example":{"workerPoolName":"general","replicas":5}}}},"responses":{"200":{"description":"Worker pool scaled","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterScaled"},"example":{"success":true,"message":"Done."}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"409":{"description":"Conflicts with the current state; read it again and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Conflicts with the current state; read it again and retry."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"scale \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"scale\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchK8sClustersClustersScale","description":"Sets a worker pool's node count. Body: `{ \"workerPoolName\": \"workers\", \"replicas\": 3 }`."}},"/k8s-clusters/{namespace}/clusters/{name}/kubelet":{"patch":{"summary":"Update the customer-facing kubelet config (BOC","description":"Sets KdcCluster.spec.kubelet (maxPods, kubeReserved, systemReserved, evictionHard). Empty/cleared body removes spec.kubelet. Takes effect on NEW nodes (existing kubelets are not live-reconfigured).\n","tags":["Managed Clusters"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["kubelet"],"properties":{"kubelet":{"type":["object","null"],"description":"Kubelet settings (KdcCluster spec.kubelet) for new nodes; null clears them."}}},"example":{"kubelet":{"maxPods":250,"systemReserved":{"cpu":"250m","memory":"512Mi"}}}}}},"responses":{"200":{"description":"Kubelet config updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubeletUpdated"},"example":{"success":true,"message":"Done.","kubelet":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"kubelet \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"kubelet\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"operationId":"patchK8sClustersClustersKubelet"}},"/k8s-clusters/{namespace}/clusters/{name}/expose":{"patch":{"summary":"Enable or disable the public HTTPS route for the Managed Cluster API server","tags":["Managed Clusters"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"},"publicAPIAllowedCIDRs":{"type":"array","maxItems":32,"items":{"type":"string"},"description":"IPv4 CIDRs for a ProjectInternal public API. Omit to preserve the list; use [] to open access."}}},"example":{"enabled":true}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterExposure"},"example":{"success":true,"enabled":true,"changed":true}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"expose \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"expose\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"operationId":"patchK8sClustersClustersExpose","description":"Publishes the cluster's API server on a public HTTPS route, or removes it. Body: `{ \"enabled\": true }`."}},"/k8s-clusters/{namespace}/clusters/{name}/events":{"get":{"summary":"Get events for a Managed Cluster","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"responses":{"200":{"description":"List of Managed Cluster events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterItems"},"example":{"items":[{}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"events \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"events\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getK8sClustersClustersEvents","description":"Recent Kubernetes events about the cluster and its parts, newest first."}},"/k8s-clusters/{namespace}/clusters/{name}/controlplane-usage":{"get":{"summary":"CPU/memory requests summed across this cluster's control-plane pods","tags":["Managed Clusters"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ControlPlaneUsage"},"example":{"items":[{"name":"web-1","cpu":"2","memory":"4Gi"}],"totals":{"cpu":"2","memory":"4Gi"}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"controlplane-usage \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"controlplane-usage\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"operationId":"getK8sClustersClustersControlplaneUsage","description":"CPU and memory requested by the cluster's control-plane pods, which count against the project's quota."}},"/k8s-clusters/{namespace}/datastores":{"get":{"summary":"List available shared datastores","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of datastores","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatastoreList"},"example":{"items":[{"name":"web-1","namespace":"acme-web","phase":"Running","etcdReady":true,"etcdReplicas":2,"exposure":"exposure","referenceCount":2,"endpoint":"https://web.acme-web.kube-dc.example","port":443,"createdAt":"2026-10-01T09:30:00Z"}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"datastores \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"datastores\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getK8sClustersDatastores","description":"Shared etcd datastores in the project that new clusters can use, with how many clusters use each."}},"/k8s-clusters/{namespace}/datastores/used-ports":{"get":{"summary":"Get ports already in use by datastores","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of used ports and suggestions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatastorePorts"},"example":{"usedPorts":[],"suggestedPort":32380,"availablePorts":[32380,32381]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"used-ports \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"used-ports\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getK8sClustersDatastoresUsedPorts","description":"Ports taken by the project's datastores, and a free one to suggest for a new datastore."}},"/k8s-clusters/{namespace}/versions":{"get":{"summary":"Get available Kubernetes versions","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of available versions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesVersionOptions"},"example":{"versions":[{"value":"v1.36.1","label":"v1.36.1 (Latest)"},{"value":"v1.35.0","label":"v1.35.0"}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getK8sClustersVersions","description":"Kubernetes versions a new cluster can run."}},"/k8s-clusters/{namespace}/kubevirt-images":{"get":{"summary":"Get available KubeVirt worker images","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of KubeVirt images","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkerImageOptions"},"example":{"images":[{"value":"docker.io/shalb/ubuntu-2404-container-disk:v1.36.1","label":"Ubuntu 24.04 + K8s v1.36.1","architecture":"amd64","default":true,"k8sVersion":"v1.36.1"},{"value":"docker.io/shalb/ubuntu-2404-container-disk:v1.35.2","label":"Ubuntu 24.04 + K8s v1.35.2","architecture":"amd64","default":false,"k8sVersion":"v1.35.0"}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getK8sClustersKubevirtImages","description":"Worker node images available for KubeVirt worker pools, with their Kubernetes version and architecture."}},"/k8s-clusters/{namespace}/clusters/{name}/upgrade-info":{"get":{"summary":"Get upgrade availability for a Managed Cluster","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"responses":{"200":{"description":"Upgrade information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeInfo"},"example":{"currentVersion":"1","latestVersion":"1","isLatest":true,"upgradeAvailable":true,"upgradeVersion":"1","upgradeImage":"upgrade-image","catalogSource":"catalog-source","catalogUnavailable":true}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"upgrade-info \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"upgrade-info\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getK8sClustersClustersUpgradeInfo","description":"Whether a newer Kubernetes version is available for the cluster, and which."}},"/k8s-clusters/{namespace}/clusters/{name}/upgrade":{"post":{"summary":"Upgrade a Managed Cluster to a new Kubernetes version","tags":["Managed Clusters"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"targetVersion":{"type":"string"},"targetImage":{"type":"string"}}},"example":{"targetVersion":"v1.34.1"}}}},"responses":{"200":{"description":"Upgrade initiated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UpgradeStarted"},"example":{"success":true,"message":"Done.","previousVersion":"1","targetVersion":"1","targetImage":"target-image","workerImagePatches":[{}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"A required service is unavailable; retry later."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"upgrade \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"upgrade\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postK8sClustersClustersUpgrade","description":"Upgrades the cluster to a newer Kubernetes version (see upgrade-info for what is available). Worker nodes are replaced as part of it; follow progress in the cluster's status. Body: `{ \"targetVersion\": \"v1.33.1\", \"targetImage\": \"...\" }` (image optional)."}},"/k8s-clusters/{namespace}/clusters/{name}/worker-pools/{pool}/autoscaling":{"get":{"summary":"Read a worker pool's autoscaling spec and observed state","tags":["Managed Clusters"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PoolAutoscaling"},"example":{"pool":"general","replicas":2,"autoscaling":{},"status":{}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"autoscaling \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"autoscaling\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."},{"name":"pool","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the worker pool."}],"operationId":"getK8sClustersClustersWorkerPoolsAutoscaling","description":"A worker pool's autoscaling settings and what the autoscaler currently observes."},"patch":{"summary":"Configure a worker pool's autoscaling (EKS-like min/max)","tags":["Managed Clusters"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"mode":{"type":"string","enum":["Builtin","ClusterAutoscaler"],"description":"Builtin (default) only ever ADDS nodes. ClusterAutoscaler hands the node count to upstream cluster-autoscaler — the only mode that also REMOVES idle nodes; requires minReplicas >= 1, and the manual scale endpoint returns 409 for such pools. Omitted fields are MERGED over the stored block (metrics: [] is the explicit clear).\n"},"minReplicas":{"type":"integer"},"maxReplicas":{"type":"integer"},"metrics":{"type":"array","items":{"type":"object"},"description":"HorizontalPodAutoscaler-style metric specs."},"behavior":{"type":"object","description":"scaleUp/scaleDown tuning; scaleDown.enabled is the per-pool node-removal switch (ClusterAutoscaler mode).\n"}}},"example":{"enabled":true,"mode":"Builtin","minReplicas":2,"maxReplicas":6,"metrics":[{"type":"cpu","targetAverageUtilization":75}]}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PoolAutoscalingUpdated"},"example":{"success":true,"pool":"general","applied":{},"autoscaling":{},"adjustedReplicas":2,"warning":"warning"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"autoscaling \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"autoscaling\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the managed cluster."},{"name":"pool","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the worker pool."}],"operationId":"patchK8sClustersClustersWorkerPoolsAutoscaling","description":"Turns autoscaling on or off for a worker pool and sets its minimum and maximum size. Fields left out keep their values."}},"/configure/{namespace}/cpu/{vm_name}":{"patch":{"summary":"Update VM CPU cores","tags":["VM Configuration"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"vm_name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."},{"in":"query","name":"cpu","required":true,"schema":{"type":"integer"},"description":"Number of CPU cores"}],"responses":{"200":{"description":"VM CPU updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"cpu \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"cpu\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchConfigureCpuByVmName","description":"Sets the VM's CPU cores (query: `cpu`). The running VM picks up the change after a reboot."}},"/configure/{namespace}/memory/{vm_name}":{"patch":{"summary":"Update VM memory","tags":["VM Configuration"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"vm_name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."},{"in":"query","name":"memory","required":true,"schema":{"type":"string"},"description":"Memory amount (e.g., 4Gi)"}],"responses":{"200":{"description":"VM memory updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"memory \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"memory\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchConfigureMemoryByVmName","description":"Sets the VM's memory (query: `memory`, for example 4Gi). The running VM picks up the change after a reboot."}},"/configure/{namespace}/console-credentials/{vm_name}":{"get":{"summary":"Reveal the generated console (VNC) login for a VM","description":"Only present for Linux VMs created after console-password generation shipped; older VMs and Windows VMs 404 here (no credentials were ever generated) — SSH remains the fallback in that case.\n","tags":["VM Configuration"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"vm_name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."}],"responses":{"200":{"description":"Console username/password","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ConsoleCredentials"},"example":{"success":true,"username":"jdoe","password":"<password>"}}}},"404":{"description":"No console credentials exist for this VM"}},"operationId":"getConfigureConsoleCredentialsByVmName"}},"/configure/{namespace}/termination/{vm_name}":{"patch":{"summary":"Update VM termination grace period","tags":["VM Configuration"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"vm_name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."},{"in":"query","name":"terminationGracePeriodSeconds","required":true,"schema":{"type":"integer"},"description":"Seconds the VM gets to shut down cleanly before it is stopped."}],"responses":{"200":{"description":"VM termination grace period updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"termination \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"termination\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchConfigureTerminationByVmName","description":"Sets how long the VM gets to shut down cleanly before it is stopped (query: `terminationGracePeriodSeconds`)."}},"/configure/{namespace}/readiness/{vm_name}":{"patch":{"summary":"Update VM readiness probe","tags":["VM Configuration"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"vm_name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."},{"in":"query","name":"failureThreshold","schema":{"type":"integer"},"description":"Failed probes in a row before the VM counts as not ready."},{"in":"query","name":"initialDelaySeconds","schema":{"type":"integer"},"description":"Seconds after start before the first probe."},{"in":"query","name":"periodSeconds","schema":{"type":"integer"},"description":"Seconds between probes."},{"in":"query","name":"timeoutSeconds","schema":{"type":"integer"},"description":"Seconds a probe may take."}],"responses":{"200":{"description":"VM readiness probe updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"readiness \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"readiness\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchConfigureReadinessByVmName","description":"Sets the VM's readiness probe timing. Query: `failureThreshold`, `initialDelaySeconds`, `periodSeconds`, `timeoutSeconds`."}},"/configure/{namespace}/gpu/{vm_name}":{"patch":{"summary":"Attach, resize, or remove a GPU on an existing VM","description":"KubeVirt does not support hot-adding a GPU to a running VM — the VM must be Stopped, same as changing any other passthrough device. This only edits spec.template.spec.domain.devices.gpus; the caller is responsible for stopping the VM first and starting it afterward.\n","tags":["VM Configuration"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"vm_name","required":true,"schema":{"type":"string"},"description":"Name of the virtual machine."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"profileId":{"type":["string","null"],"description":"GPU catalog profile ID to attach, or null/omitted to remove any attached GPU."},"count":{"type":"integer","description":"Number of devices from the profile to attach (default 1)."}}},"example":{"profileId":"nvidia-v100-passthrough","count":1}}}},"responses":{"200":{"description":"VM GPU configuration updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"409":{"description":"VM is not Stopped"},"422":{"description":"GPU request failed catalog/capacity/quota validation"}},"operationId":"patchConfigureGpuByVmName"}},"/cloud-shell/{namespace}/generate":{"get":{"summary":"Generate cloud shell terminal","tags":["Cloud Shell"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Cloud shell terminal generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShellSession"},"example":{"svc_id":"svc_id"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getCloudShellGenerate","description":"Starts a browser terminal for the project with kubectl and the kube-dc CLI signed in as the caller, and returns its id. Poll the status endpoint until it is ready."}},"/cloud-shell/{namespace}/generate-project-console":{"get":{"summary":"Generate project console terminal","tags":["Cloud Shell"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Project console terminal generated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShellSession"},"example":{"svc_id":"svc_id"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getCloudShellGenerateProjectConsole","description":"Starts a project console terminal and returns its id, like the cloud shell."}},"/cloud-shell/{namespace}/status":{"get":{"summary":"Check if cloud shell service is ready","tags":["Cloud Shell"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"query","name":"svc_id","schema":{"type":"string"},"description":"Terminal id returned when the shell was started."}],"responses":{"200":{"description":"Service status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ShellStatus"},"example":{"ready":true,"message":"Done.","ip":"ip","port":443}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCloudShellStatus","description":"Whether the project's terminal is ready to connect to."}},"/system/{namespace}/ingresses":{"get":{"summary":"List all ingresses in a Project","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project backing namespace"}],"responses":{"200":{"description":"List of ingresses","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"ingresses \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"ingresses\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemIngresses","description":"The project's Ingresses as a Kubernetes list."}},"/system/{namespace}/ingresses/{name}":{"get":{"summary":"Get a specific ingress","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project backing namespace"},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Ingress name"}],"responses":{"200":{"description":"Ingress details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"404":{"description":"Ingress not found"}},"operationId":"getSystemIngressesByName","description":"One Ingress as stored by Kubernetes."},"delete":{"summary":"Delete an ingress","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Ingress."}],"responses":{"200":{"description":"Ingress deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"ingresses \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"ingresses\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemIngressesByName","description":"Deletes the Ingress. Its backend Service is not affected."}},"/system/{namespace}/ingresses/{name}/logs":{"get":{"summary":"Get ingress logs","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Ingress."}],"responses":{"200":{"description":"Ingress logs","content":{"text/plain":{"schema":{"type":"string"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getSystemIngressesLogs","description":"Logs of a running pod behind the Ingress's backend Service, as plain text. 404 when the Ingress has no backend Service or the Service has no running pods."}},"/system/{namespace}/ingresses/delete":{"post":{"summary":"Bulk delete ingresses","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"names":{"type":"array","items":{"type":"string"}}}},"example":{"names":["web"]}}}},"responses":{"200":{"description":"Ingresses deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postSystemIngressesDelete","description":"Deletes several Ingresses in one call. Body: `{ \"ingressNames\": [...] }`. The response counts successes and failures and lists a result per name."}},"/system/{namespace}/statefulsets":{"get":{"summary":"List all StatefulSets in a Project","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of statefulsets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"statefulsets \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"statefulsets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemStatefulsets","description":"The project's StatefulSets as a Kubernetes list."}},"/system/{namespace}/statefulsets/{name}":{"get":{"summary":"Get a specific statefulset","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the StatefulSet."}],"responses":{"200":{"description":"Statefulset details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"statefulsets \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"statefulsets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemStatefulsetsByName","description":"One StatefulSet as stored by Kubernetes."},"delete":{"summary":"Delete a statefulset","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the StatefulSet."}],"responses":{"200":{"description":"Statefulset deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"statefulsets \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"statefulsets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemStatefulsetsByName","description":"Deletes the StatefulSet. Its pods are removed by Kubernetes; PersistentVolumeClaims created from its volume templates are kept."}},"/system/{namespace}/statefulsets/{name}/logs":{"get":{"summary":"Get statefulset logs","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the StatefulSet."}],"responses":{"200":{"description":"Statefulset logs","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getSystemStatefulsetsLogs","description":"The last 1000 log lines of the StatefulSet's first pod, as plain text."}},"/system/{namespace}/statefulsets/delete":{"post":{"summary":"Bulk delete statefulsets","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["statefulSetNames"],"properties":{"statefulSetNames":{"type":"array","minItems":1,"items":{"type":"string"}}}},"example":{"statefulSetNames":["redis"]}}}},"responses":{"200":{"description":"Statefulsets deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postSystemStatefulsetsDelete","description":"Deletes several StatefulSets in one call. Body: `{ \"statefulSetNames\": [\"db\", \"cache\"] }`. Each name is deleted independently; the response counts successes and failures and lists a result per name."}},"/system/{namespace}/replicationcontrollers":{"get":{"summary":"List all ReplicationControllers in a Project","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of replication controllers","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"replicationcontrollers \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"replicationcontrollers\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemReplicationcontrollers","description":"The project's ReplicationControllers as a Kubernetes list. Tenants usually may not list them; the 403 Status is returned as is."}},"/system/{namespace}/replicasets":{"get":{"summary":"List all ReplicaSets in a Project","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of replicasets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"replicasets \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"replicasets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemReplicasets","description":"The project's ReplicaSets as a Kubernetes list."}},"/system/{namespace}/replicasets/{name}":{"get":{"summary":"Get a specific replicaset","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the ReplicaSet."}],"responses":{"200":{"description":"Replicaset details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"replicasets \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"replicasets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemReplicasetsByName","description":"One ReplicaSet as stored by Kubernetes."},"delete":{"summary":"Delete a replicaset","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the ReplicaSet."}],"responses":{"200":{"description":"Replicaset deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"replicasets \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"replicasets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemReplicasetsByName","description":"Deletes the ReplicaSet and its pods. A ReplicaSet owned by a Deployment is recreated by it."}},"/system/{namespace}/replicasets/{name}/logs":{"get":{"summary":"Get replicaset logs","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the ReplicaSet."}],"responses":{"200":{"description":"Replicaset logs","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getSystemReplicasetsLogs","description":"The last 1000 log lines of the ReplicaSet's first pod, as plain text."}},"/system/{namespace}/replicasets/delete":{"post":{"summary":"Bulk delete replicasets","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["replicaSetNames"],"properties":{"replicaSetNames":{"type":"array","minItems":1,"items":{"type":"string"}}}},"example":{"replicaSetNames":["web-6d4f8b7c9"]}}}},"responses":{"200":{"description":"Replicasets deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postSystemReplicasetsDelete","description":"Deletes several ReplicaSets in one call. Body: `{ \"replicaSetNames\": [...] }`. The response counts successes and failures and lists a result per name."}},"/system/{namespace}/jobs":{"get":{"summary":"List all Jobs in a Project","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of jobs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"jobs \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"jobs\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemJobs","description":"The project's Jobs as a Kubernetes list."}},"/system/{namespace}/jobs/{name}":{"get":{"summary":"Get a specific job","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Job."}],"responses":{"200":{"description":"Job details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Kubernetes could not be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes answered with something other than JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the Job does not exist).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"jobs \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"jobs\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemJobsByName","description":"One Job as stored by Kubernetes."},"delete":{"summary":"Delete a job","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Job."}],"responses":{"200":{"description":"Job deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Kubernetes could not be reached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes answered with something other than JSON.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the Job does not exist).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"jobs \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"jobs\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemJobsByName","description":"Deletes the Job and its pods."}},"/system/{namespace}/jobs/{name}/logs":{"get":{"summary":"Get job logs","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Job."}],"responses":{"200":{"description":"Job logs","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getSystemJobsLogs","description":"The full log of the Job's first pod, as plain text."}},"/system/{namespace}/jobs/delete":{"post":{"summary":"Bulk delete jobs","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["jobNames"],"properties":{"jobNames":{"type":"array","minItems":1,"items":{"type":"string"}}}},"example":{"jobNames":["db-migrate"]}}}},"responses":{"200":{"description":"Jobs deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postSystemJobsDelete","description":"Deletes several Jobs in one call. Body: `{ \"jobNames\": [...] }`. The response counts successes and failures and lists a result per name."}},"/system/{namespace}/daemonsets":{"get":{"summary":"List all DaemonSets in a Project","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of daemonsets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"daemonsets \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"daemonsets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemDaemonsets","description":"The project's DaemonSets as a Kubernetes list."}},"/system/{namespace}/daemonsets/{name}":{"get":{"summary":"Get a specific daemonset","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the DaemonSet."}],"responses":{"200":{"description":"Daemonset details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"daemonsets \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"daemonsets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemDaemonsetsByName","description":"One DaemonSet as stored by Kubernetes."},"delete":{"summary":"Delete a daemonset","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the DaemonSet."}],"responses":{"200":{"description":"Daemonset deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"daemonsets \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"daemonsets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemDaemonsetsByName","description":"Deletes the DaemonSet and its pods."}},"/system/{namespace}/daemonsets/{name}/logs":{"get":{"summary":"Get daemonset logs","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the DaemonSet."}],"responses":{"200":{"description":"Daemonset logs","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getSystemDaemonsetsLogs","description":"The last 1000 log lines of the DaemonSet's first pod, as plain text."}},"/system/{namespace}/daemonsets/delete":{"post":{"summary":"Bulk delete daemonsets","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["daemonSetNames"],"properties":{"daemonSetNames":{"type":"array","minItems":1,"items":{"type":"string"}}}},"example":{"daemonSetNames":["log-agent"]}}}},"responses":{"200":{"description":"Daemonsets deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postSystemDaemonsetsDelete","description":"Deletes several DaemonSets in one call. Body: `{ \"daemonSetNames\": [...] }`. The response counts successes and failures and lists a result per name."}},"/system/{namespace}/pods":{"get":{"summary":"List all Pods in a Project","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project backing namespace"}],"responses":{"200":{"description":"List of pods","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"pods \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"pods\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemPods","description":"The project's pods as a Kubernetes list. Pods that use a GPU carry an extra `kubeDCGPUStatus` field describing the GPU's state."}},"/system/{namespace}/pods/{name}":{"get":{"summary":"Get a specific pod","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project backing namespace"},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Pod name"}],"responses":{"200":{"description":"Pod details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"404":{"description":"Pod not found"}},"operationId":"getSystemPodsByName","description":"One pod as stored by Kubernetes."}},"/system/{namespace}/pods/{name}/logs":{"get":{"summary":"Get pod logs","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project backing namespace"},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Pod name"}],"responses":{"200":{"description":"Pod logs","content":{"text/plain":{"schema":{"type":"string"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"logs \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"logs\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemPodsLogs","description":"Up to the last 2000 lines (1 MiB) of a pod's log with timestamps, as plain text. Optional query: `container` (defaults to the only or first container) and `previous=true` for the previous, crashed instance."}},"/system/{namespace}/pod/{name}":{"delete":{"summary":"Delete a pod","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project backing namespace"},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Pod name"}],"responses":{"200":{"description":"Pod deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"404":{"description":"Pod not found"}},"operationId":"deleteSystemPodByName","description":"Deletes the pod. A pod owned by a controller (Deployment, StatefulSet, Job) is recreated by it."}},"/system/{namespace}/pods/delete":{"post":{"summary":"Bulk delete pods","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["podNames"],"properties":{"podNames":{"type":"array","minItems":1,"items":{"type":"string"}}}},"example":{"podNames":["web-6d4f8b7c9-x2kqp"]}}}},"responses":{"200":{"description":"Pods deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postSystemPodsDelete","description":"Deletes several pods in one call. Body: `{ \"podNames\": [...] }`. The response counts successes and failures and lists a result per name."}},"/system/{namespace}/deployments":{"get":{"summary":"List all Deployments in a Project","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of deployments","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"deployments \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"deployments\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemDeployments","description":"The project's Deployments as a Kubernetes list."}},"/system/{namespace}/deployments/{name}":{"get":{"summary":"Get a specific deployment","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Deployment."}],"responses":{"200":{"description":"Deployment details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"deployments \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"deployments\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemDeploymentsByName","description":"One Deployment as stored by Kubernetes."},"delete":{"summary":"Delete a deployment","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Deployment."}],"responses":{"200":{"description":"Deployment deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"deployments \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"deployments\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemDeploymentsByName","description":"Deletes the Deployment with its ReplicaSets and pods."}},"/system/{namespace}/deployments/{name}/logs":{"get":{"summary":"Get deployment logs","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Deployment."}],"responses":{"200":{"description":"Deployment logs","content":{"text/plain":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"text/plain":{"schema":{"type":"string"},"example":"Internal error."}}}},"operationId":"getSystemDeploymentsLogs","description":"The last 1000 log lines of the Deployment's first pod (found by its label selector), as plain text. Use the pod logs endpoint to read a specific pod."}},"/system/{namespace}/deployments/delete":{"post":{"summary":"Bulk delete deployments","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["deploymentNames"],"properties":{"deploymentNames":{"type":"array","minItems":1,"items":{"type":"string"}}}},"example":{"deploymentNames":["web"]}}}},"responses":{"200":{"description":"Deployments deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postSystemDeploymentsDelete","description":"Deletes several Deployments in one call. Body: `{ \"deploymentNames\": [...] }`. The response counts successes and failures and lists a result per name."}},"/system/{namespace}/services":{"get":{"summary":"List all Services in a Project","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of services","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"services \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"services\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemServices","description":"The project's Services as a Kubernetes list, including LoadBalancer Services."}},"/system/{namespace}/services/{name}":{"get":{"summary":"Get a specific service","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Service."}],"responses":{"200":{"description":"Service details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"services \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"services\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemServicesByName","description":"One Service as stored by Kubernetes."},"delete":{"summary":"Delete a service","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Service."}],"responses":{"200":{"description":"Service deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"services \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"services\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemServicesByName","description":"Deletes the Service. Deleting a LoadBalancer Service releases its external IP."}},"/system/{namespace}/services/delete":{"post":{"summary":"Bulk delete services","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["serviceNames"],"properties":{"serviceNames":{"type":"array","minItems":1,"items":{"type":"string"}}}},"example":{"serviceNames":["web"]}}}},"responses":{"200":{"description":"Services deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BulkDeleteResult"},"example":{"total":2,"successful":1,"failed":1,"results":[{"success":true,"status":1,"response":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"error":"Request failed."}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postSystemServicesDelete","description":"Deletes several Services in one call. Body: `{ \"serviceNames\": [...] }`. The response counts successes and failures and lists a result per name."}},"/system/{namespace}/configmaps":{"get":{"summary":"List all ConfigMaps in a Project","tags":["ConfigMaps & Kubernetes Secrets"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of configmaps","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"kind":"ConfigMapList","apiVersion":"v1","metadata":{"resourceVersion":"660488809"},"items":[{"metadata":{"name":"kube-dc-trusted-ca","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-000000000013","resourceVersion":"660487736","creationTimestamp":"2026-10-03T00:57:29Z","labels":{"app.kubernetes.io/managed-by":"kube-dc","kube-dc.com/inject-trusted-ca":"true"},"annotations":{"propagate.hnc.x-k8s.io/none":"true"}}},{"metadata":{"name":"kube-root-ca.crt","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-000000000014","resourceVersion":"660487507","creationTimestamp":"2026-10-03T00:57:25Z","annotations":{"kubernetes.io/description":"Contains a CA bundle that can be used to verify the kube-apiserver when using internal endpoints such as the internal service IP or kubernetes.default.svc. No other usage is guaranteed across distributions of Kubernetes clusters."}},"data":{"ca.crt":"-----BEGIN CERTIFICATE-----\n…"}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"configmaps \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"configmaps\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemConfigmaps","description":"The project's ConfigMaps as a Kubernetes list."}},"/system/{namespace}/configmaps/{name}":{"get":{"summary":"Get a specific configmap","tags":["ConfigMaps & Kubernetes Secrets"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the ConfigMap."}],"responses":{"200":{"description":"ConfigMap details","content":{"application/yaml":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"configmaps \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"configmaps\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemConfigmapsByName","description":"One ConfigMap as stored by Kubernetes."},"put":{"summary":"Update a configmap","tags":["ConfigMaps & Kubernetes Secrets"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the ConfigMap."}],"requestBody":{"required":true,"content":{"application/yaml":{"schema":{"type":"string","description":"The full configmap manifest as YAML. Include metadata.resourceVersion from the last read."},"example":"apiVersion: v1\nkind: ConfigMap\nmetadata:\n  name: web-config\n  namespace: acme-web\n  resourceVersion: \"184702\"\ndata:\n  LOG_LEVEL: info\n  FEATURE_FLAGS: checkout,search\n"}}},"responses":{"200":{"description":"ConfigMap updated","content":{"application/yaml":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"configmaps \"web-1\" is forbidden: User \"jane@acme.example\" cannot update resource \"configmaps\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"putSystemConfigmapsByName","description":"Replaces the ConfigMap with the object in the body. Include metadata.resourceVersion from the last read to avoid overwriting a concurrent change."},"delete":{"summary":"Delete a configmap","tags":["ConfigMaps & Kubernetes Secrets"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the ConfigMap."}],"responses":{"200":{"description":"ConfigMap deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"configmaps \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"configmaps\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemConfigmapsByName","description":"Deletes the ConfigMap. Pods that mount it keep their copy until they restart."}},"/system/{namespace}/secrets":{"get":{"summary":"List all Secrets in a Project","tags":["ConfigMaps & Kubernetes Secrets"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of secrets","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"secrets \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"secrets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemSecrets","description":"The project's Kubernetes Secrets, values included (base64), as a Kubernetes list. For secrets with version history and audit, use the Secrets API."}},"/system/{namespace}/secrets/{name}":{"get":{"summary":"Get a specific secret","tags":["ConfigMaps & Kubernetes Secrets"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Kubernetes Secret."}],"responses":{"200":{"description":"Secret details","content":{"application/yaml":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"secrets \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"secrets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getSystemSecretsByName","description":"One Kubernetes Secret, values included (base64)."},"put":{"summary":"Update a secret","tags":["ConfigMaps & Kubernetes Secrets"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Kubernetes Secret."}],"requestBody":{"required":true,"content":{"application/yaml":{"schema":{"type":"string","description":"The full secret manifest as YAML. Include metadata.resourceVersion from the last read."},"example":"apiVersion: v1\nkind: Secret\nmetadata:\n  name: web-env\n  namespace: acme-web\n  resourceVersion: \"184711\"\ntype: Opaque\nstringData:\n  API_URL: https://api.example.com\n"}}},"responses":{"200":{"description":"Secret updated","content":{"application/yaml":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"secrets \"web-1\" is forbidden: User \"jane@acme.example\" cannot update resource \"secrets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"putSystemSecretsByName","description":"Replaces the Secret with the object in the body. Values in `data` are base64; include metadata.resourceVersion from the last read."},"delete":{"summary":"Delete a secret","tags":["ConfigMaps & Kubernetes Secrets"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Kubernetes Secret."}],"responses":{"200":{"description":"Secret deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"secrets \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"secrets\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemSecretsByName","description":"Deletes the Kubernetes Secret. A secret synced from the Secrets API is recreated by its sync; delete it there instead."}},"/system/{namespace}/service/{name}":{"delete":{"summary":"Delete a service (alternative endpoint)","tags":["Services & Ingress"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the Service."}],"responses":{"200":{"description":"Service deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"An upstream service answered unexpectedly."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"service \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"service\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteSystemServiceByName","description":"Same as DELETE /system/{namespace}/services/{name}; kept for older clients."}},"/system/{namespace}/tree-structure":{"get":{"summary":"Get a Project resource tree","tags":["Workloads"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project backing namespace"}],"responses":{"200":{"description":"Tree structure of Project resources","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TreeNode"}},"example":[{"id":1980,"name":"Workloads","children":[{"id":1982,"name":"Daemon Sets"},{"id":1983,"name":"Deployments"}]},{"id":1989,"name":"Discovery and Load Balancer","children":[{"id":1991,"name":"Ingresses"},{"id":1992,"name":"Services"}]}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getSystemTreeStructure","description":"The static menu of resource kinds the console shows for a project (Workloads, Discovery and Load Balancer, Config and Storage). Holds no project data."}},"/system/{namespace}/kubeconfig":{"get":{"summary":"Get a kubeconfig setup script for a Project","tags":["Organization"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"query","name":"organization","description":"Organization to sign in to.","schema":{"type":"string"}},{"in":"query","name":"project","description":"Project to select after signing in.","schema":{"type":"string"}},{"in":"query","name":"os","description":"Platform of the CLI binary to install.","schema":{"type":"string","enum":["linux_amd64","linux_arm64","darwin_amd64","darwin_arm64","windows_amd64"],"default":"linux_amd64"}},{"in":"query","name":"clusterName","description":"The console's host name (for example console.kube-dc.cloud); the installation domain is taken from it.","schema":{"type":"string"}},{"in":"query","name":"format","description":"json to get the script with its context as JSON; plain text otherwise.","schema":{"type":"string","enum":["json"]}}],"responses":{"200":{"description":"The setup script, as text or (with format=json) inside JSON.","content":{"text/plain":{"schema":{"type":"string"}},"application/json":{"schema":{"$ref":"#/components/schemas/KubeconfigSetup"},"example":{"script":"script","currentOs":"current-os","domain":"domain","organization":"acme","project":"web","osOptions":[{"id":"linux_amd64","name":"web-1"}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getSystemKubeconfig","description":"Shell commands that install the kube-dc CLI and sign in to the project, for the console's \"Connect\" dialog. Query: `organization`, `project`, `os` (`linux_amd64` by default; `linux_arm64`, `darwin_amd64`, `darwin_arm64`, `windows_amd64`) and `clusterName`."}},"/system/features":{"get":{"summary":"Cluster feature flags surfaced to the UI","description":"Returns the cluster-level feature gates the UI needs to render\nconditional controls (e.g. hide the egressNetworkType=public\nradio button when the cluster has opted out via master-config\n`allow_public_projects: false`). The values come from env vars\nsourced by the backend Deployment from the master-config Secret,\nso they reflect the manager's authoritative view.\n\nThis endpoint is intentionally tiny — adding fields here is the\ncanonical place for future \"should the UI show X?\" flags.\nSee kube-dc/docs/prd/public-projects-gate.md.\n\n`payg` is true only on a pay-as-you-go installation (the backend\nis wired to the billing service); the managed-service quote and\nbudget routes exist only then.\n","tags":["Platform"],"responses":{"200":{"description":"Feature-flag object","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"features":{"type":"object","properties":{"allowPublicProjects":{"type":"boolean"},"tenantVlan":{"type":"boolean"},"payg":{"type":"boolean"}}}}},"example":{"success":true,"features":{"allowPublicProjects":false,"tenantVlan":true,"payg":true}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getSystemFeatures"}},"/system/next-project-cidr":{"get":{"summary":"Suggested VPC CIDR block for a new project","description":"Returns the next free per-project VPC block so the create-project\nform can prefill a range nobody else is using, instead of the\n10.0.0.0/16 every project used to share.\n\nWhy it matters: overlapping project CIDRs are fine for the OVN\ndata plane (each project is its own VPC), but kube-ovn's\ncustom-VPC health-check TProxy keys probe targets by pod IP\nalone, so two PROBED pods that share an IP on one node send each\nother's kubelet probes into the wrong netns and get liveness-\nkilled. Upstream documents this and has not fixed it as of\nv1.16.x. Distinct blocks make the collision impossible between\nprojects created this way.\n\nThis is a SUGGESTION only — the field stays editable and the API\nstill accepts any valid CIDR. Overlap remains legal (the\ncollision-descheduler CronJob covers the rare case).\n\nUses the backend service account so it sees projects across ALL\norganizations; a user token would only reveal the caller's own\norg and could hand out a block another org already holds.\n","tags":["Organization"],"responses":{"200":{"description":"Suggested block. `exhausted: true` uses the legacy fallback when the pool is full.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NextProjectCidr"},"example":{"success":true,"cidrBlock":"10.0.20.0/22"}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Not signed in, or the session expired.","code":"OK"}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Your role does not allow this.","code":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"A required service is unavailable; retry later.","code":"OK"}}}}},"operationId":"getSystemNextProjectCidr"}},"/register":{"post":{"summary":"Register a new user account","tags":["Registration"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","password","firstName","lastName"],"properties":{"email":{"type":"string"},"password":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"}}},"example":{"email":"jane@acme.example","password":"correct-horse-battery-staple","firstName":"Jane","lastName":"Doe"}}}},"responses":{"200":{"description":"User created, verification email sent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationResult"},"example":{"success":true,"message":"Done.","email":"jane@acme.example","requiresOrgSetup":true}}}},"400":{"description":"Validation error"},"409":{"description":"User already exists"}},"operationId":"postRegister","description":"Creates an account and sends a verification email. Body: `email`, `password`, `firstName`, `lastName`. An existing address gets a hint to verify or sign in instead."}},"/register/resend-verification":{"post":{"summary":"Resend verification email","tags":["Registration"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string"}}},"example":{"email":"jane@acme.example"}}}},"responses":{"200":{"description":"Verification email resent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessage"},"example":{"success":true,"message":"Done."}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Invalid request; the message says which field.","code":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Internal error.","code":"OK"}}}}},"operationId":"postRegisterResendVerification","description":"Sends the verification email again."}},"/register/check-org/{orgName}":{"get":{"summary":"Check if organization name is available","tags":["Registration"],"parameters":[{"in":"path","name":"orgName","required":true,"schema":{"type":"string"},"description":"Organization name to check."}],"responses":{"200":{"description":"Organization availability status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgNameAvailability"},"example":{"success":true,"orgName":"acme","exists":true,"available":true,"message":"Done."}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Invalid request; the message says which field.","code":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Internal error.","code":"OK"}}}}},"operationId":"getRegisterCheckOrgByOrgName","description":"Whether an organization name is free to use."}},"/register/org":{"post":{"summary":"Create a new organization (user becomes admin)","tags":["Registration"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orgName","password"],"properties":{"orgName":{"type":"string","description":"Organization name (lowercase, letters, numbers, hyphens)"},"password":{"type":"string","description":"Password for the organization admin user (min 8 chars)"},"firstProjectName":{"type":"string","description":"Name of the first project (optional, defaults to 'default')"}}},"example":{"orgName":"acme","password":"correct-horse-battery-staple","firstProjectName":"web"}}}},"responses":{"200":{"description":"Organization created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationCreated"},"example":{"success":true,"message":"Done.","organization":"acme","project":"web","role":"org-admin","billingMode":"payg","redirectUrl":"https://web.acme-web.kube-dc.example","token":"<token>","refreshToken":"refresh-token","promoTrialActivated":true,"promoTrialDetails":{}}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"409":{"description":"Organization already exists"}},"operationId":"postRegisterOrg","description":"Creates an organization with the signed-up user as its admin, and its first project. Body: `orgName`, `firstProjectName` (default \"default\"), `password`, and optional `promoCode` and `billingMode`. Needs a token from the sign-up realm."}},"/register/join-request":{"post":{"summary":"Request to join an existing organization","tags":["Registration"],"security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["orgName"],"properties":{"orgName":{"type":"string"}}},"example":{"orgName":"acme"}}}},"responses":{"200":{"description":"Join request submitted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SuccessMessage"},"example":{"success":true,"message":"Done."}}}},"400":{"description":"Validation error"},"401":{"description":"Unauthorized"},"404":{"description":"Organization not found"}},"operationId":"postRegisterJoinRequest","description":"Asks to join an existing organization. Body: `{ \"orgName\": \"acme\" }`. Its admins are notified and decide. Needs a token from the sign-up realm."}},"/object-storage/{namespace}/quota":{"get":{"summary":"Get S3 storage quota and usage for the organization","tags":["Object Storage"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Quota limits and current usage","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectStorageQuotaResponse"},"example":{"success":true,"data":{"enabled":true,"organization":"acme","phase":"Ready","quotas":{"maxSize":"20G","maxBuckets":5,"maxObjects":100000},"usage":{"bucketCount":1,"sizeBytes":0,"objectCount":0,"usageUnavailable":false},"userQuota":{"enabled":true,"check_on_raw":false,"max_size":20000000000,"max_size_kb":19531250,"max_objects":100000}},"timestamp":"2026-10-03T00:57:49.223Z"}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not found.","status":404,"message":"Not found."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"getObjectStorageQuota","description":"The organization's object storage limits (size, buckets, objects) and current usage."}},"/object-storage/{namespace}/endpoint":{"get":{"summary":"Get S3 endpoint information","tags":["Object Storage"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"S3 endpoint URL and connection info","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectStorageEndpointResponse"},"example":{"success":true,"data":{"endpoint":"https://s3.kube-dc.example","region":"us-east-1","pathStyle":true,"protocol":"https"},"timestamp":"2026-10-03T00:57:49.228Z"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getObjectStorageEndpoint","description":"The S3 endpoint, region and addressing style to configure S3 clients with."}},"/object-storage/{namespace}/buckets/{name}/policy":{"get":{"summary":"Get bucket access policy","tags":["Object Storage"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BucketPolicyResponse"},"example":{"success":true,"data":{"access":"private","policy":null},"timestamp":"2026-10-03T00:58:28.295Z"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"operationId":"getObjectStorageBucketsPolicy","description":"Whether the bucket is private or allows anonymous reads."},"put":{"summary":"Set bucket access policy (public-read or private)","tags":["Object Storage"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"access":{"type":"string","enum":["public-read","private"]}}},"example":{"access":"public-read"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BucketPolicyResponse"},"example":{"success":true,"data":{"access":"private"},"timestamp":"2026-10-03T00:58:28.345Z","message":"Bucket access set to private"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"operationId":"putObjectStorageBucketsPolicy","description":"Makes the bucket private or publicly readable. Body: `{ \"access\": \"private\" | \"public-read\" }`."}},"/object-storage/{namespace}/buckets/{name}/objects":{"get":{"summary":"List objects in a bucket (supports prefix/delimiter for folder browsing)","tags":["Object Storage"],"parameters":[{"in":"query","name":"prefix","schema":{"type":"string"},"description":"Folder to list, with a trailing slash; empty for the bucket root."},{"in":"query","name":"delimiter","schema":{"type":"string","default":"/"},"description":"Character that separates folder levels (default `/`)."},{"in":"query","name":"maxKeys","schema":{"type":"integer","default":1000},"description":"Most entries to return (default 1000)."},{"in":"query","name":"continuationToken","schema":{"type":"string"},"description":"Token from the previous page's `nextContinuationToken`."},{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectListResponse"},"example":{"success":true,"data":{"objects":[{"name":"a.txt","key":"docs/a.txt","type":"file","size":8,"lastModified":"2026-10-03T00:58:28.021Z","etag":"\"800c327aefb3f9241513cbf551abbfda\""}],"prefix":"docs/","isTruncated":false,"nextContinuationToken":null,"keyCount":2},"timestamp":"2026-10-03T00:58:28.076Z"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getObjectStorageBucketsObjects","description":"Lists objects one level at a time, like a folder view. Query: `prefix` (the folder), `delimiter` (default `/`), `maxKeys` (default 1000), `continuationToken` for the next page."},"delete":{"summary":"Delete an object from a bucket","tags":["Object Storage"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"}}},"example":{"key":"images/logo.png"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectKeyResponse"},"example":{"success":true,"data":{"key":"docs/","deleted":1},"timestamp":"2026-10-03T00:58:28.972Z","message":"Folder deleted (1 objects)"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"operationId":"deleteObjectStorageBucketsObjects","description":"Deletes one object. Body: `{ \"key\": \"path/to/file\" }`."}},"/object-storage/{namespace}/buckets/{name}/upload-url":{"post":{"summary":"Get a presigned URL for uploading an object","tags":["Object Storage"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"},"contentType":{"type":"string"}}},"example":{"key":"images/logo.png","contentType":"image/png"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresignedUrlResponse"},"example":{"success":true,"data":{"url":"https://s3.kube-dc.example/acme-web-assets/docs/c.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=REDACTED&X-Amz-Date=20261003T005828Z&X-Amz-Expires=3600&X-Amz-Signature=REDACTED&X-Amz-SignedHeaders=host","key":"docs/c.txt","expiresIn":3600},"timestamp":"2026-10-03T00:58:28.254Z"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"operationId":"postObjectStorageBucketsUploadUrl","description":"A presigned URL that uploads one object with a PUT, valid for an hour. Body: `{ \"key\": \"path/to/file\", \"contentType\": \"image/png\" }`."}},"/object-storage/{namespace}/buckets/{name}/upload":{"post":{"summary":"Proxy upload — file goes through backend to S3 (avoids CORS issues)","tags":["Object Storage"],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","required":["file","key"],"properties":{"file":{"type":"string","format":"binary"},"key":{"type":"string","description":"Object key to write, including any folder prefix."}}},"example":{"key":"reports/2026/q3.csv","file":"q3.csv"}}}},"responses":{"200":{"description":"Object uploaded","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectKeyResponse"},"example":{"success":true,"data":{"key":"docs/a.txt","size":8},"timestamp":"2026-10-03T00:58:28.035Z","message":"File uploaded"}}}},"400":{"description":"No file or no key"}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"operationId":"postObjectStorageBucketsUpload","description":"Uploads a file through the backend, for clients that cannot use a presigned URL (for example because of browser CORS rules)."}},"/object-storage/{namespace}/buckets/{name}/download-url":{"post":{"summary":"Get a presigned URL for downloading an object","tags":["Object Storage"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string"}}},"example":{"key":"reports/2026/q3.csv"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PresignedUrlResponse"},"example":{"success":true,"data":{"url":"https://s3.kube-dc.example/acme-web-assets/docs/b.txt?X-Amz-Algorithm=AWS4-HMAC-SHA256&X-Amz-Content-Sha256=UNSIGNED-PAYLOAD&X-Amz-Credential=REDACTED&X-Amz-Date=20261003T005828Z&X-Amz-Expires=3600&X-Amz-Signature=REDACTED&X-Amz-SignedHeaders=host","key":"docs/b.txt","expiresIn":3600},"timestamp":"2026-10-03T00:58:28.238Z"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"operationId":"postObjectStorageBucketsDownloadUrl","description":"A presigned URL that downloads one object, valid for an hour. Body: `{ \"key\": \"path/to/file\" }`."}},"/object-storage/{namespace}/buckets/{name}/move":{"post":{"summary":"Move/rename an object (server-side copy + delete)","tags":["Object Storage"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"sourceKey":{"type":"string"},"destinationKey":{"type":"string"}}},"example":{"sourceKey":"images/logo.png","destinationKey":"images/archive/logo-2025.png"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectMovedResponse"},"example":{"success":true,"data":{"sourceKey":"docs/a.txt","destinationKey":"docs/b.txt"},"timestamp":"2026-10-03T00:58:28.147Z","message":"Object moved"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"operationId":"postObjectStorageBucketsMove","description":"Moves or renames an object by copying it and deleting the original. Body: `{ \"sourceKey\": \"a.txt\", \"destinationKey\": \"docs/a.txt\" }`."}},"/object-storage/{namespace}/buckets/{name}/folders":{"post":{"summary":"Create a folder (empty object with trailing slash)","tags":["Object Storage"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"key":{"type":"string","description":"Folder path ending with /"}}},"example":{"key":"images/archive/"}}}},"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectKeyResponse"},"example":{"success":true,"data":{"key":"docs/"},"timestamp":"2026-10-03T00:58:27.966Z","message":"Folder created"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"operationId":"postObjectStorageBucketsFolders","description":"Creates an empty folder marker. Body: `{ \"key\": \"docs/\" }`; a trailing slash is added if missing."}},"/object-storage/{namespace}/keys":{"get":{"summary":"Get org-level S3 access keys","tags":["Object Storage"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"S3 access keys for the organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectStorageCredentialsResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"accessKeyId":"AKIAEXAMPLE0WEB1","secretAccessKey":"<secret access key>","endpoint":"https://web.acme-web.kube-dc.example","organization":"acme"}}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not found.","status":404,"message":"Not found."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"getObjectStorageKeys","description":"The organization's primary S3 access key and secret, with the endpoint. Treat the response as a secret."}},"/object-storage/{namespace}/keys/all":{"get":{"summary":"List all S3 access keys for the organization","tags":["Object Storage"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ObjectStorageKeyListResponse"},"example":{"success":true,"data":{"keys":[{"accessKey":"UPAAACX3A5G4OSZ2L08N","user":"acme","secretKeyHint":"****Eurj"}],"endpoint":"https://s3.kube-dc.example","organization":"acme"},"timestamp":"2026-10-03T00:57:48.709Z"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"operationId":"getObjectStorageKeysAll","description":"Every S3 access key of the organization. Secrets are not returned, only the last characters as a hint."}},"/object-storage/{namespace}/keys/generate":{"post":{"summary":"Generate a new S3 access key for the organization","tags":["Object Storage"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AccessKeyCreatedResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"accessKey":"AKIAEXAMPLE0WEB1","secretKey":"secret-key","user":"jdoe"}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"generate \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"generate\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"operationId":"postObjectStorageKeysGenerate","description":"Creates an additional S3 access key for the organization. The secret is returned once; store it."}},"/object-storage/{namespace}/keys/{accessKey}":{"delete":{"summary":"Revoke an S3 access key","tags":["Object Storage"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgSuccess"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done."}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not found.","status":404,"message":"Not found."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"accessKey","in":"path","required":true,"schema":{"type":"string"},"description":"The S3 access key id to revoke."}],"operationId":"deleteObjectStorageKeysByAccessKey","description":"Revokes the access key. Clients using it lose access immediately."}},"/object-storage/{namespace}/buckets":{"get":{"summary":"List S3 buckets in a Project","tags":["Object Storage"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of buckets with their status and credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BucketListResponse"},"example":{"success":true,"data":{"buckets":[{"name":"managed-k8s-backups","bucketName":"acme-web-managed-k8s-backups","storageClass":"ceph-bucket","phase":"Bound","createdAt":"2026-10-03T00:57:33Z","endpoint":"rook-ceph-rgw-my-store.rook-ceph.svc","port":"80","region":"","hasCredentials":true}],"count":1},"timestamp":"2026-10-03T00:57:48.617Z"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"getObjectStorageBuckets","description":"The project's buckets with their state and S3 endpoint."},"post":{"summary":"Create a new S3 bucket","tags":["Object Storage"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"}}},"example":{"name":"assets"}}}},"responses":{"200":{"description":"Bucket created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BucketCreatedResponse"},"example":{"success":true,"data":{"name":"assets","bucketName":"acme-web-assets","phase":"Pending"},"timestamp":"2026-10-03T00:58:22.488Z","message":"Bucket creation initiated"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"postObjectStorageBuckets","description":"Creates a bucket. Body: `{ \"name\": \"assets\" }`. The platform provisions it asynchronously; it is usable once its phase is Bound."}},"/object-storage/{namespace}/buckets/{name}":{"delete":{"summary":"Delete an S3 bucket","tags":["Object Storage"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"responses":{"200":{"description":"Bucket deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/NameResponse"},"example":{"success":true,"data":{"name":"assets"},"timestamp":"2026-10-03T00:58:29.029Z","message":"Bucket deleted"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"deleteObjectStorageBucketsByName","description":"Deletes the bucket's claim. With the default bucket storage class (reclaim policy Delete) the bucket itself is removed; empty it first to be sure nothing is kept."},"get":{"summary":"Get bucket details including credentials","tags":["Object Storage"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the bucket."}],"responses":{"200":{"description":"Bucket details with S3 credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BucketDetailResponse"},"example":{"success":true,"data":{"name":"assets","bucketName":"acme-web-assets","storageClass":"ceph-bucket","phase":"Bound","createdAt":"2026-10-03T00:58:22Z","credentials":{"accessKeyId":"9L4V1VI31MU1DZZOACKY","secretAccessKey":"<redacted>"},"config":{"host":"rook-ceph-rgw-my-store.rook-ceph.svc","port":"80","name":"acme-web-assets","region":""},"s3Endpoint":"https://s3.kube-dc.example"},"timestamp":"2026-10-03T00:58:27.818Z"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"getObjectStorageBucketsByName","description":"One bucket with its endpoint and the credentials to access it."}},"/manage-organization/vlans":{"get":{"summary":"Datacenter VLANs allocated to this organization","tags":["Organization"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VlanListResponse"},"example":{"success":true,"enabled":true,"items":[{}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Invalid request; the message says which field.","code":"OK"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Not found.","code":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Internal error.","code":"OK"}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"An upstream service answered unexpectedly.","code":"OK"}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"vlans \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"vlans\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getManageOrganizationVlans","description":"Datacenter VLAN segments the platform has allocated to the organization, with the project each one is assigned to. 404 when tenant VLANs are not enabled on the installation."}},"/manage-organization/vlans/{segment}/assign":{"post":{"summary":"Assign an allocated VLAN to one of the organization's projects","tags":["Organization"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["project"],"properties":{"project":{"type":"string","description":"Project name (not namespace)."}}},"example":{"project":"web"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VlanAssignResult"},"example":{"success":true,"network":"network"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Invalid request; the message says which field.","code":"OK"}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Your role does not allow this.","code":"OK"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Not found.","code":"OK"}}}},"409":{"description":"Conflicts with the current state; read it again and retry.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Conflicts with the current state; read it again and retry.","code":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Internal error.","code":"OK"}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"An upstream service answered unexpectedly.","code":"OK"}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"assign \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"assign\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"name":"segment","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the VLAN segment allocated to the organization."}],"operationId":"postManageOrganizationVlansAssign","description":"Attaches one of the organization's VLAN segments to a project, so its VMs can join that layer-2 network. Body: `{ \"project\": \"web\" }`. Requires org-admin."},"delete":{"summary":"Unassign a VLAN, returning it to the organization's pool","description":"The allocation SURVIVES this — the wire goes back to the org's pool, not\nto the platform admin, which is what makes assignment reversible without\na ticket. Teardown drains attached workloads first, so the wire is not\nimmediately re-assignable.\n","tags":["Organization"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VlanReleaseResult"},"example":{"success":true,"state":"releasing"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Invalid request; the message says which field.","code":"OK"}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Your role does not allow this.","code":"OK"}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Not found.","code":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Internal error.","code":"OK"}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"An upstream service answered unexpectedly.","code":"OK"}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"assign \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"assign\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"name":"segment","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the VLAN segment allocated to the organization."}],"operationId":"deleteManageOrganizationVlansAssign"}},"/manage-organization/users":{"get":{"summary":"List all users in organization","tags":["Organization"],"responses":{"200":{"description":"List of users from Keycloak","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgUserListResponse"},"example":{"success":true,"data":[{"id":"3f2504e0-4f89-41d3-9a0c-000000000004","name":"admin admin","email":"jane@acme.example","roles":["org-admin"],"status":"Active","joinedAt":"2026-08-25T15:55:49.570Z","permissions":{"canManageProjects":true,"canManageUsers":true,"canViewResources":true}}],"timestamp":"2026-10-03T00:57:50.112Z","total":1,"source":"keycloak-api","keycloak":{"available":true,"realm":"acme","url":"https://login.kube-dc.example"}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getManageOrganizationUsers","description":"Users of the organization's Keycloak realm with their groups (roles). Requires org-admin."},"post":{"summary":"Create a new user","tags":["Organization"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"},"email":{"type":"string"},"firstName":{"type":"string"},"lastName":{"type":"string"},"password":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}}}},"example":{"username":"jdoe","email":"jane@acme.example","firstName":"Jane","lastName":"Doe","password":"correct-horse-battery-staple","roles":["user"]}}}},"responses":{"200":{"description":"User created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgUserResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","name":"web-1","email":"jane@acme.example","roles":["developer"],"status":"Active","joinedAt":"2026-10-01T09:30:00Z"}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not signed in, or the session expired.","status":401,"message":"Not signed in, or the session expired."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"postManageOrganizationUsers","description":"Creates a user in the organization's realm with a permanent password and puts them in the given groups (`roles`). Body: `username`, `email`, `firstName`, `lastName`, `password`, `roles`, `enabled`. Requires org-admin."}},"/manage-organization/users/{userId}":{"delete":{"summary":"Delete a user","tags":["Organization"],"parameters":[{"in":"path","name":"userId","required":true,"schema":{"type":"string"},"description":"Keycloak user id (a UUID), as listed by the users endpoint."}],"responses":{"200":{"description":"User deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgUserDeletedResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"userId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not signed in, or the session expired.","status":401,"message":"Not signed in, or the session expired."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"deleteManageOrganizationUsersByUserId","description":"Deletes the user from the organization's realm, ending their access to every project. Requires org-admin."}},"/manage-organization/users/{userId}/groups":{"get":{"summary":"Get user's groups","tags":["Organization"],"parameters":[{"in":"path","name":"userId","required":true,"schema":{"type":"string"},"description":"Keycloak user id (a UUID), as listed by the users endpoint."}],"responses":{"200":{"description":"List of user's groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserGroupsResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":["data"],"userId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","total":2}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"getManageOrganizationUsersGroups","description":"The realm groups the user belongs to, which grant their organization and project roles."},"put":{"summary":"Assign or remove groups for user","tags":["Organization"],"parameters":[{"in":"path","name":"userId","required":true,"schema":{"type":"string"},"description":"Keycloak user id (a UUID), as listed by the users endpoint."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"groups":{"type":"array","items":{"type":"string"}},"action":{"type":"string","enum":["assign","remove"]}}},"example":{"groups":["developers"],"action":"assign"}}}},"responses":{"200":{"description":"Groups updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/UserGroupsChangeResponse"},"example":{"success":true,"data":{"userId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","action":"assign","results":[{}],"summary":{"total":2,"successful":1,"failed":1}}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not signed in, or the session expired.","status":401,"message":"Not signed in, or the session expired."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"putManageOrganizationUsersGroups","description":"Adds the user to groups or removes them. Body: `{ \"groups\": [...], \"action\": \"assign\" | \"remove\" }` (assign by default). Requires org-admin."}},"/manage-organization/users/available-groups":{"get":{"summary":"Get available Keycloak base groups (org-admin, user only)","tags":["Organization"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AvailableGroupListResponse"},"example":{"success":true,"data":[{"id":"3f2504e0-4f89-41d3-9a0c-000000000008","name":"org-admin","displayName":"org-admin","description":"Manage this Organization and its Projects","type":"base","path":"/org-admin"},{"id":"3f2504e0-4f89-41d3-9a0c-000000000009","name":"user","displayName":"user","description":"Read-only access to the Organization and its Projects","type":"base","path":"/user"}],"timestamp":"2026-10-03T00:57:50.167Z","total":2,"baseGroupsCount":2,"orgGroupsCount":0,"organization":"acme"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"getManageOrganizationUsersAvailableGroups","description":"Groups a user can be put in, the base roles (org-admin, user) plus the organization's OrganizationGroups."}},"/manage-organization/roles":{"get":{"summary":"Get roles for a specific project","tags":["Organization"],"parameters":[{"in":"query","name":"projectId","required":true,"schema":{"type":"string"},"description":"Project identifier"}],"responses":{"200":{"description":"List of roles in project","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectRoleListResponse"},"example":{"success":true,"data":[{"id":"acme-web/deployer","name":"deployer","namespace":"acme-web","project":"web","scope":"Project","description":"No description available","createdAt":"2026-10-03T00:58:29Z","rules":[{"verbs":["get","list"],"apiGroups":[""],"resources":["configmaps"]}],"resourceCount":1,"verbCount":2,"permissions":[{"apiGroups":[""],"resources":["configmaps"],"verbs":["get","list"],"resourceNames":[]}],"labels":{},"annotations":{}},{"id":"acme-web/admin","name":"admin","namespace":"acme-web","project":"web","scope":"Project","description":"Manage supported Project resources and namespaced RBAC; quotas remain read-only","createdAt":"2026-10-03T00:57:31Z","rules":[{"verbs":["get","list"],"apiGroups":[""],"resources":["persistentvolumeclaims","services"]},{"verbs":["create"],"apiGroups":[""],"resources":["serviceaccounts/token"]}],"resourceCount":112,"verbCount":173,"permissions":[{"apiGroups":[""],"resources":["persistentvolumeclaims","services"],"verbs":["get","list"],"resourceNames":[]},{"apiGroups":[""],"resources":["serviceaccounts/token"],"verbs":["create"],"resourceNames":[]}],"labels":{},"annotations":{"description":"Manage supported Project resources and namespaced RBAC; quotas remain read-only"}}],"timestamp":"2026-10-03T00:58:29.210Z","total":5,"organization":"acme","organizationRoles":0,"projectRoles":5,"projectId":"web"}}}},"403":{"description":"Access denied - org-admin role required"}},"operationId":"getManageOrganizationRoles","description":"Kubernetes Roles of one project (query: `projectId`), which organization groups grant to their members."},"post":{"summary":"Create a new role for a specific project","tags":["Organization"],"parameters":[{"in":"query","name":"projectId","required":true,"schema":{"type":"string"},"description":"Project identifier"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metadata","rules"],"properties":{"metadata":{"type":"object","properties":{"name":{"type":"string"}}},"rules":{"type":"array","description":"Kubernetes RBAC PolicyRules.","items":{"type":"object"}}}},"example":{"metadata":{"name":"deployer"},"rules":[{"apiGroups":["apps"],"resources":["deployments"],"verbs":["get","list","watch","update","patch"]},{"apiGroups":[""],"resources":["pods"],"verbs":["get","list","watch"]},{"apiGroups":[""],"resources":["pods/log"],"verbs":["get","list"]}]}}}},"responses":{"200":{"description":"Role created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectRoleResponse"},"example":{"success":true,"data":{"id":"acme-web/deployer","name":"deployer","namespace":"acme-web","project":"web","scope":"Project","description":"No description available","createdAt":"2026-10-03T00:58:29Z","rules":[{"verbs":["get","list"],"apiGroups":[""],"resources":["configmaps"]}],"resourceCount":1,"verbCount":2,"permissions":[{"apiGroups":[""],"resources":["configmaps"],"verbs":["get","list"],"resourceNames":[]}],"labels":{},"annotations":{}},"timestamp":"2026-10-03T00:58:29.148Z","message":"Role 'deployer' created successfully in project web"}}}},"403":{"description":"Access denied - org-admin role required"}},"operationId":"postManageOrganizationRoles","description":"Creates a Kubernetes Role in a project (query: `projectId`) from a name and RBAC rules. Requires org-admin."}},"/manage-organization/roles/{roleName}":{"put":{"summary":"Update an existing role for a specific project","tags":["Organization"],"parameters":[{"in":"path","name":"roleName","required":true,"schema":{"type":"string"},"description":"Name of the role to update"},{"in":"query","name":"projectId","required":true,"schema":{"type":"string"},"description":"Project identifier"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metadata","rules"],"properties":{"metadata":{"type":"object"},"rules":{"type":"array","description":"Kubernetes RBAC PolicyRules.","items":{"type":"object"}}}},"example":{"metadata":{"name":"deployer"},"rules":[{"apiGroups":["apps"],"resources":["deployments","statefulsets"],"verbs":["get","list","watch","update","patch"]}]}}}},"responses":{"200":{"description":"Role updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectRoleResponse"},"example":{"success":true,"data":{"id":"acme-web/deployer","name":"deployer","namespace":"acme-web","project":"web","scope":"Project","description":"No description available","createdAt":"2026-10-03T00:58:29Z","rules":[{"verbs":["get"],"apiGroups":[""],"resources":["configmaps"]}],"resourceCount":1,"verbCount":1,"permissions":[{"apiGroups":[""],"resources":["configmaps"],"verbs":["get"],"resourceNames":[]}],"labels":{},"annotations":{}},"timestamp":"2026-10-03T00:58:29.263Z","message":"Role 'deployer' updated successfully in project web"}}}},"403":{"description":"Access denied - org-admin role required"}},"operationId":"putManageOrganizationRolesByRoleName","description":"Replaces the rules of a project Role (query: `projectId`). Requires org-admin."},"delete":{"summary":"Delete a role from a specific project","tags":["Organization"],"parameters":[{"in":"path","name":"roleName","required":true,"schema":{"type":"string"},"description":"Name of the role to delete"},{"in":"query","name":"projectId","required":true,"schema":{"type":"string"},"description":"Project identifier"}],"responses":{"200":{"description":"Role deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectRoleDeletedResponse"},"example":{"success":true,"data":{"deleted":true,"roleName":"deployer","projectId":"web"},"timestamp":"2026-10-03T00:58:29.428Z","message":"Role 'deployer' deleted successfully from project web"}}}},"403":{"description":"Access denied - org-admin role required"}},"operationId":"deleteManageOrganizationRolesByRoleName","description":"Deletes a project Role (query: `projectId`). Groups that granted it lose that access. Requires org-admin."}},"/manage-organization/projects":{"get":{"summary":"List all projects in organization","tags":["Organization"],"responses":{"200":{"description":"List of projects with detailed information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgProjectListResponse"},"example":{"success":true,"data":[{"id":"web","name":"web","uid":"3f2504e0-4f89-41d3-9a0c-000000000002","displayName":"web","description":"","status":"Ready","statusDetails":{"conditions":[{"lastTransitionTime":"2026-10-03T00:57:25Z","message":"NamespaceCreate successfully finished","reason":"CreateSync","status":"True","type":"NamespaceSync"},{"lastTransitionTime":"2026-10-03T00:57:39Z","message":"HierarchyConfiguration in sync (recovered from transient failure)","reason":"Sync","status":"True","type":"HierarchyConfigurationSync"}],"namespace":"acme-web","quotaUsage":{"cpu":{"hard":"4","used":"0"},"cpuBreakdown":{"platformOverhead":"0","workloads":"0"},"lastUpdated":"2026-10-03T00:57:35Z","memory":{"hard":"8Gi","used":"0Gi"},"pods":{"hard":"100","used":"0"},"storage":{"hard":"60Gi","used":"0Gi"}},"ready":true,"security":{"certificateManager":{"ready":true},"databaseCredentials":{"ready":true},"databaseMount":"database-web","kms":{"ready":true},"kvMount":"kv-web","secretStoreName":"openbao","secretsManager":{"ready":true},"servicePublicationMount":"kube-dc-service-kv-3f2504e0-4f89-41d3-9a0c-000000000002","servicePublicationSecretStore":"openbao-services","servicePublicationServiceAccount":"openbao-services-3f2504e0-4f89-41d3-9a0c-000000000002","syncServiceAccount":"openbao-external-secrets"}},"createdAt":"2026-10-03T00:57:25Z","labels":{},"annotations":{"kube-dc.com/security-status-updated-at":"2026-10-03T00:57:35.839426661Z"},"resourceQuotas":[{"name":"hrq.hnc.x-k8s.io","hard":{"limits.cpu":"4","limits.memory":"8Gi","pods":"100","requests.cpu":"4","requests.memory":"8Gi","requests.storage":"60Gi","services.loadbalancers":"100"},"used":{"limits.cpu":"0","limits.memory":"0","pods":"0","requests.cpu":"0","requests.memory":"0","requests.storage":"0","services.loadbalancers":"0"}}],"resources":{"pods":{"total":0,"running":0}},"spec":{"cidrBlock":"10.0.16.0/22","egressNetworkType":"cloud"}}],"timestamp":"2026-10-03T00:57:50.202Z","total":1}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"getManageOrganizationProjects","description":"The organization's projects with their readiness, quota usage and security services (secrets, certificates, KMS) state."},"post":{"summary":"Create a new project","tags":["Organization"],"requestBody":{"required":true,"content":{"application/yaml":{"schema":{"type":"string"},"example":"apiVersion: kube-dc.com/v1\nkind: Project\nmetadata:\n  name: web\n  namespace: acme\nspec:\n  egressNetworkType: cloud\n"}}},"responses":{"200":{"description":"Project created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgProjectResponse"},"example":{"success":true,"data":{"apiVersion":"kube-dc.com/v1","kind":"Project","metadata":{"creationTimestamp":"2026-10-03T00:57:25Z","generation":1,"name":"web","namespace":"acme","resourceVersion":"660487490","uid":"3f2504e0-4f89-41d3-9a0c-000000000002"},"spec":{"egressNetworkType":"cloud"}},"timestamp":"2026-10-03T00:57:25.506Z","message":"Project 'web' created successfully"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not signed in, or the session expired.","status":401,"message":"Not signed in, or the session expired."}}}},"402":{"description":"A billing subscription is required first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"A billing subscription is required first.","status":402,"message":"A billing subscription is required first."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"A required service is unavailable; retry later.","status":503,"message":"A required service is unavailable; retry later."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"postManageOrganizationProjects","description":"Creates a project from a Project manifest sent as YAML (`Content-Type: application/yaml`). The platform then creates its namespace, network and access roles; watch `status` for readiness. Requires org-admin."}},"/manage-organization/projects/{projectId}":{"get":{"summary":"Get project details","tags":["Organization"],"parameters":[{"in":"path","name":"projectId","required":true,"schema":{"type":"string"},"description":"Project name within the organization (not its namespace)."}],"responses":{"200":{"description":"Project details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgProjectResponse"},"example":{"success":true,"data":{"apiVersion":"kube-dc.com/v1","kind":"Project","metadata":{"annotations":{"kube-dc.com/security-status-updated-at":"2026-10-03T00:58:24.964358385Z"},"creationTimestamp":"2026-10-03T00:57:25Z","deletionGracePeriodSeconds":0,"deletionTimestamp":"2026-10-03T00:58:29Z","finalizers":["project.kube-dc.com/finalizer"],"generation":3,"name":"web","namespace":"acme","resourceVersion":"660493649","uid":"3f2504e0-4f89-41d3-9a0c-000000000002"},"spec":{"cidrBlock":"10.0.16.0/22","egressNetworkType":"cloud"},"status":{"conditions":[{"lastTransitionTime":"2026-10-03T00:59:26Z","message":"NamespaceDelete failed: *v1.Namespace wait for delete timeout","reason":"DeleteSync","status":"False","type":"NamespaceSync"},{"lastTransitionTime":"2026-10-03T00:57:39Z","message":"HierarchyConfiguration in sync (recovered from transient failure)","reason":"Sync","status":"True","type":"HierarchyConfigurationSync"}],"namespace":"acme-web","quotaUsage":{},"ready":false,"security":{"certificateManager":{"ready":true},"databaseCredentials":{"ready":true},"databaseMount":"database-web","kms":{"ready":true},"kvMount":"kv-web","secretStoreName":"openbao","secretsManager":{"ready":true},"servicePublicationMount":"kube-dc-service-kv-3f2504e0-4f89-41d3-9a0c-000000000002","servicePublicationSecretStore":"openbao-services","servicePublicationServiceAccount":"openbao-services-3f2504e0-4f89-41d3-9a0c-000000000002","syncServiceAccount":"openbao-external-secrets"}},"namespace":{}},"timestamp":"2026-10-03T00:59:50.855Z"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"getManageOrganizationProjectsByProjectId","description":"The Project object as stored, including its status."},"delete":{"summary":"Delete a project","description":"Request asynchronous project teardown. Console clients send the displayed UID to protect same-name replacements; a mismatch returns 409. With a UID, the controller owns cleanup. Omit the body only for legacy clients.","tags":["Organization"],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"uid":{"type":"string","minLength":1,"description":"UID of the Project confirmed for deletion."}}},"example":{"uid":"96ff15e6-c05e-4eaf-8381-b50c4003f084"}}}},"parameters":[{"in":"path","name":"projectId","required":true,"schema":{"type":"string"},"description":"Project name within the organization (not its namespace)."}],"responses":{"200":{"description":"Project deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgProjectResponse"},"example":{"success":true,"data":{"apiVersion":"kube-dc.com/v1","kind":"Project","metadata":{"annotations":{"kube-dc.com/security-status-updated-at":"2026-10-03T00:58:24.964358385Z"},"creationTimestamp":"2026-10-03T00:57:25Z","deletionGracePeriodSeconds":0,"deletionTimestamp":"2026-10-03T00:58:29Z","finalizers":["project.kube-dc.com/finalizer"],"generation":3,"name":"web","namespace":"acme","resourceVersion":"660490780","uid":"3f2504e0-4f89-41d3-9a0c-000000000002"},"spec":{"cidrBlock":"10.0.16.0/22","egressNetworkType":"cloud"},"status":{"conditions":[{"lastTransitionTime":"2026-10-03T00:57:25Z","message":"NamespaceCreate successfully finished","reason":"CreateSync","status":"True","type":"NamespaceSync"},{"lastTransitionTime":"2026-10-03T00:57:39Z","message":"HierarchyConfiguration in sync (recovered from transient failure)","reason":"Sync","status":"True","type":"HierarchyConfigurationSync"}],"namespace":"acme-web","quotaUsage":{"cpu":{"hard":"4","used":"0"},"cpuBreakdown":{"platformOverhead":"0","workloads":"0"},"lastUpdated":"2026-10-03T00:58:22Z","memory":{"hard":"8Gi","used":"0Gi"},"pods":{"hard":"100","used":"0"},"storage":{"hard":"60Gi","used":"0Gi"}},"ready":true,"security":{"certificateManager":{"ready":true},"databaseCredentials":{"ready":true},"databaseMount":"database-web","kms":{"ready":true},"kvMount":"kv-web","secretStoreName":"openbao","secretsManager":{"ready":true},"servicePublicationMount":"kube-dc-service-kv-3f2504e0-4f89-41d3-9a0c-000000000002","servicePublicationSecretStore":"openbao-services","servicePublicationServiceAccount":"openbao-services-3f2504e0-4f89-41d3-9a0c-000000000002","syncServiceAccount":"openbao-external-secrets"}}},"timestamp":"2026-10-03T00:58:30.238Z","message":"Project 'web' deleted successfully"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not signed in, or the session expired.","status":401,"message":"Not signed in, or the session expired."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"operationId":"deleteManageOrganizationProjectsByProjectId"}},"/manage-organization/projects/{projectId}/quota":{"get":{"summary":"Get per-project quota details (usage, limits, org HRQ remaining)","description":"Reads the Project with your token first. Deleting projects return 409 without querying their namespace quotas.","tags":["Organization"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectQuotaResponse"},"example":{"success":true,"data":{"projectNamespace":"acme-web","projectQuota":null,"hrqQuotas":[{"name":"hrq.hnc.x-k8s.io","hard":{"limits.cpu":"4","limits.memory":"8Gi","pods":"100","requests.cpu":"4","requests.memory":"8Gi","requests.storage":"60Gi","services.loadbalancers":"100"},"used":{"limits.cpu":"0","limits.memory":"0","pods":"0","requests.cpu":"0","requests.memory":"0","requests.storage":"0","services.loadbalancers":"0"}}],"orgHRQ":{"hard":{"limits.cpu":"4","limits.memory":"8Gi","pods":"100","requests.cpu":"4","requests.memory":"8Gi","requests.storage":"60Gi","services.loadbalancers":"100"},"used":{"limits.cpu":"0","limits.memory":"0","pods":"0","requests.cpu":"0","requests.memory":"0","requests.storage":"0","services.loadbalancers":"0"}},"gpuProfiles":[],"limitRanges":[{"name":"default-resource-limits","limits":[{"type":"Container","max":{"cpu":"4","memory":"8Gi"},"min":{"cpu":"1m","memory":"1Mi"},"default":{"cpu":"500m","memory":"512Mi"},"defaultRequest":{"cpu":"100m","memory":"128Mi"}},{"type":"Pod","max":{"cpu":"4","memory":"8Gi"}}]}],"publicIPv4Used":0},"timestamp":"2026-10-03T00:57:50.342Z"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"},"description":"Project name within the organization (not its namespace)."}],"operationId":"getManageOrganizationProjectsQuota"},"delete":{"summary":"Remove per-project ResourceQuota (org-admin only)","tags":["Organization"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ProjectQuotaRemovedResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"pooled":true,"action":"delete"}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}}},"parameters":[{"name":"projectId","in":"path","required":true,"schema":{"type":"string"},"description":"Project name within the organization (not its namespace)."}],"operationId":"deleteManageOrganizationProjectsQuota","description":"Removes the project's own quota, so it draws freely from the organization's quota. Requires org-admin."},"put":{"summary":"Set project quota","description":"Sets the project's resource limits. Requires org-admin. Send any of the classic limits, `accelerators`, or both; `accelerators` replaces only GPU limits.","tags":["Organization"],"parameters":[{"name":"projectId","in":"path","required":true,"description":"Project name.","schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","minProperties":1,"properties":{"cpu":{"type":"string","example":"8"},"memory":{"type":"string","example":"16Gi"},"storage":{"type":"string","example":"200Gi"},"pods":{"type":"string","example":"50"},"accelerators":{"type":"object","additionalProperties":{"type":"integer"},"description":"GPU limits by accelerator class."}}},"example":{"cpu":"8","memory":"16Gi","storage":"200Gi","pods":"50"}}}},"responses":{"200":{"description":"The quota after the change.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"name":{"type":["string","null"]},"hard":{"type":"object","additionalProperties":{"type":"string"}},"used":{"type":"object","additionalProperties":{"type":"string"}},"accelerators":{"type":"object"}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"name":"web-1","hard":{"web-1":"4"},"used":{"web-1":"1"},"accelerators":{}}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"putManageOrganizationProjectsQuota"}},"/manage-organization/organization-groups":{"get":{"summary":"Get all organization groups","tags":["Organization"],"responses":{"200":{"description":"List of organization groups","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationGroupListResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":[{"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","name":"web-1","displayName":"Acme Web","description":"Acme web shop","createdAt":"2026-10-01T09:30:00Z","permissions":[{}],"labels":{"app":"labels"},"annotations":{"app":"annotations"},"spec":{"permissions":[{"project":"web","roles":["developer"]}]},"status":{},"projectCount":2,"projects":["web"],"resourceVersion":"184702"}],"total":2,"organization":"acme"}}}},"403":{"description":"Access denied - org-admin role required"}},"operationId":"getManageOrganizationOrganizationGroups","description":"The organization's groups. Each grants its members a role in one or more projects."},"post":{"summary":"Create a new organization group","tags":["Organization"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metadata","spec"],"properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"type":"object","properties":{"name":{"type":"string"},"annotations":{"type":"object"}}},"spec":{"type":"object","properties":{"permissions":{"type":"array","items":{"type":"object"}}}}}},"example":{"apiVersion":"kube-dc.com/v1","kind":"OrganizationGroup","metadata":{"name":"developers"},"spec":{"permissions":[{"project":"web","roles":["developer"]}]}}}}},"responses":{"200":{"description":"Organization group created successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationGroupResponse"},"example":{"success":true,"data":{"id":"3f2504e0-4f89-41d3-9a0c-000000000001","name":"developers","displayName":"developers","description":"","createdAt":"2026-10-03T00:58:29Z","permissions":[{"project":"web","roles":["deployer"]}],"labels":{},"annotations":{},"status":{"phase":"Unknown"},"spec":{"permissions":[{"project":"web","roles":["deployer"]}]},"projectCount":1,"projects":["web"]},"timestamp":"2026-10-03T00:58:29.300Z","message":"OrganizationGroup 'developers' created successfully"}}}},"403":{"description":"Access denied - org-admin role required"}},"operationId":"postManageOrganizationOrganizationGroups","description":"Creates an organization group with its per-project permissions; the platform creates the matching Keycloak group and role bindings. Requires org-admin."}},"/manage-organization/organization-groups/{groupId}":{"get":{"summary":"Get a specific organization group","tags":["Organization"],"parameters":[{"in":"path","name":"groupId","required":true,"schema":{"type":"string"},"description":"Organization group identifier"}],"responses":{"200":{"description":"Organization group details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationGroupResponse"},"example":{"success":true,"data":{"id":"3f2504e0-4f89-41d3-9a0c-000000000001","name":"developers","displayName":"developers","description":"","createdAt":"2026-10-03T00:58:29Z","permissions":[{"project":"web","roles":["deployer"]}],"labels":{},"annotations":{},"status":{"phase":"Unknown"},"spec":{"permissions":[{"project":"web","roles":["deployer"]}]},"projectCount":1,"projects":["web"],"resourceVersion":"660490767"},"timestamp":"2026-10-03T00:58:29.329Z"}}}},"403":{"description":"Access denied - org-admin role required"},"404":{"description":"Organization group not found"}},"operationId":"getManageOrganizationOrganizationGroupsByGroupId","description":"One organization group with its permissions and status."},"put":{"summary":"Update an organization group","tags":["Organization"],"parameters":[{"in":"path","name":"groupId","required":true,"schema":{"type":"string"},"description":"Organization group identifier"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["metadata","spec"],"properties":{"metadata":{"type":"object"},"spec":{"type":"object"}}},"example":{"metadata":{"name":"developers","resourceVersion":"184820"},"spec":{"permissions":[{"project":"web","roles":["developer","deployer"]}]}}}}},"responses":{"200":{"description":"Organization group updated successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationGroupResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","name":"web-1","displayName":"Acme Web","description":"Acme web shop","createdAt":"2026-10-01T09:30:00Z","permissions":[{}],"labels":{"app":"labels"},"annotations":{"app":"annotations"},"spec":{"permissions":[{"project":"web","roles":["developer"]}]},"status":{},"projectCount":2,"projects":["web"],"resourceVersion":"184702"}}}}},"403":{"description":"Access denied - org-admin role required"}},"operationId":"putManageOrganizationOrganizationGroupsByGroupId","description":"Replaces an organization group's display name, description and permissions. Members gain or lose project access accordingly. Requires org-admin."},"delete":{"summary":"Delete an organization group","tags":["Organization"],"parameters":[{"in":"path","name":"groupId","required":true,"schema":{"type":"string"},"description":"Organization group identifier"}],"responses":{"200":{"description":"Organization group deleted successfully","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationGroupDeletedResponse"},"example":{"success":true,"data":{"apiVersion":"kube-dc.com/v1","kind":"OrganizationGroup","metadata":{"creationTimestamp":"2026-10-03T00:58:29Z","deletionGracePeriodSeconds":0,"deletionTimestamp":"2026-10-03T00:58:29Z","finalizers":["organizationgroup.kube-dc.com/finalizer"],"generation":2,"name":"developers","namespace":"acme","resourceVersion":"660490771","uid":"3f2504e0-4f89-41d3-9a0c-000000000001"},"spec":{"permissions":[{"project":"web","roles":["deployer"]}]}},"timestamp":"2026-10-03T00:58:29.362Z","message":"OrganizationGroup 'developers' deleted successfully"}}}},"403":{"description":"Access denied - org-admin role required"},"404":{"description":"Organization group not found"}},"operationId":"deleteManageOrganizationOrganizationGroupsByGroupId","description":"Deletes the group; its members lose the project access it granted. Requires org-admin."}},"/manage-organization/join-requests":{"get":{"summary":"List pending join requests for the organization","tags":["Organization"],"security":[{"bearerAuth":[]}],"responses":{"200":{"description":"List of pending join requests","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinRequestListResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","count":2,"data":[{}]}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getManageOrganizationJoinRequests","description":"People who signed up and asked to join the organization, waiting for an admin decision. Requires org-admin."}},"/manage-organization/join-requests/{userId}/approve":{"post":{"summary":"Approve a join request","tags":["Organization"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"userId","required":true,"schema":{"type":"string"},"description":"Keycloak user id (a UUID), as listed by the users endpoint."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"group":{"type":"string","description":"Group to add user to (default \"user\")"}}},"example":{"group":"user"}}}},"responses":{"200":{"description":"Join request approved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinDecisionResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"userId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","email":"jane@acme.example","organization":"acme","group":"developers","emailSent":true}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not found.","status":404,"message":"Not found."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postManageOrganizationJoinRequestsApprove","description":"Admits the person to the organization in the given group. Body: `{ \"group\": \"user\" }` (user by default; org-admin also allowed). Requires org-admin."}},"/manage-organization/join-requests/{userId}/deny":{"post":{"summary":"Deny a join request","tags":["Organization"],"security":[{"bearerAuth":[]}],"parameters":[{"in":"path","name":"userId","required":true,"schema":{"type":"string"},"description":"Keycloak user id (a UUID), as listed by the users endpoint."}],"responses":{"200":{"description":"Join request denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/JoinDecisionResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"userId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","email":"jane@acme.example","organization":"acme","group":"developers","emailSent":true}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request; the message says which field.","status":400,"message":"Invalid request; the message says which field."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"404":{"description":"Not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not found.","status":404,"message":"Not found."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postManageOrganizationJoinRequestsDeny","description":"Declines the request and removes it from the list. Requires org-admin."}},"/manage-organization/audit":{"get":{"summary":"Get audit logs for organization","tags":["Organization"],"parameters":[{"in":"query","name":"limit","schema":{"type":"integer","default":100},"description":"Most entries to return (default 100)."},{"in":"query","name":"offset","schema":{"type":"integer","default":0},"description":"Entries to skip, for paging."},{"in":"query","name":"startDate","schema":{"type":"string"},"description":"Earliest time to include (ISO 8601)."},{"in":"query","name":"endDate","schema":{"type":"string"},"description":"Latest time to include (ISO 8601)."},{"in":"query","name":"action","schema":{"type":"string"},"description":"Only entries whose action contains this text (for example `pod.running`)."},{"in":"query","name":"user","schema":{"type":"string"},"description":"Only entries whose user contains this text."},{"in":"query","name":"resource","schema":{"type":"string"},"description":"Only entries whose resource name contains this text."}],"responses":{"200":{"description":"List of audit logs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgAuditListResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","total":2,"organization":"acme","filters":{},"pagination":{"limit":1,"offset":1,"hasMore":true},"data":[{"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","timestamp":"2026-10-01T09:30:00Z","action":"action","resource":{"kind":"Resource","name":"web-1","namespace":"acme-web"},"user":"jdoe","message":"Done.","type":"Ready","count":2,"source":"source","project":"web"}]}}}},"403":{"description":"Access denied - org-admin role required"}},"operationId":"getManageOrganizationAudit","description":"Recent Kubernetes events from the organization's project namespaces, newest first, presented as an activity log. For access to secrets and keys, use the security audit log under Audit."}},"/databases/{namespace}/databases/{name}/configure":{"patch":{"summary":"Update database resource configuration","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"cpu":{"type":"string"},"memory":{"type":"string"},"replicas":{"type":"integer"},"parameters":{"type":"object"}}},"example":{"cpu":"2","memory":"4Gi","replicas":3,"parameters":{"max_connections":"200"}}}}},"responses":{"200":{"description":"Database configuration updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseConfigured"},"example":{"success":true,"spec":{}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"configure \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"configure\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchDatabasesDatabasesConfigure","description":"Changes size, replicas, version or engine parameters. Body: any of `cpu`, `memory`, `storage`, `replicas`, `version`, `parameters`."}},"/databases/{namespace}/databases/{name}/expose":{"patch":{"summary":"Enable or disable the database's external LoadBalancer endpoint","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["enabled"],"properties":{"enabled":{"type":"boolean"}}},"example":{"enabled":true}}}},"responses":{"200":{"description":"Exposure desired state updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseExposure"},"example":{"success":true,"enabled":true,"type":"Ready","externalEndpoint":"https://web.acme-web.kube-dc.example"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"409":{"description":"Conflicts with the current state; read it again and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Conflicts with the current state; read it again and retry."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"expose \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"expose\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchDatabasesDatabasesExpose","description":"Publishes the database on an external LoadBalancer address, or removes it. Body: `{ \"enabled\": true }`."}},"/databases/status":{"get":{"summary":"Check if the KdcDatabase CRD is installed","tags":["Databases"],"responses":{"200":{"description":"CRD availability status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabasesStatus"},"example":{"enabled":true}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getDatabasesStatus","description":"Whether managed databases are installed on this platform."}},"/databases/{namespace}/config":{"get":{"summary":"Get supported database engines and versions","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Configuration options","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabasesConfig"},"example":{"engines":[{"name":"postgresql","label":"PostgreSQL","versions":[{"value":"17","label":"17"},{"value":"16","label":"16 (Default)","default":true}]},{"name":"mariadb","label":"MariaDB","versions":[{"value":"11.4","label":"11.4 (Default)","default":true},{"value":"10.11","label":"10.11"}]}],"cpuOptions":["250m","500m"],"memoryOptions":["512Mi","1Gi"],"storageOptions":["10Gi","20Gi"]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getDatabasesConfig","description":"Engines (PostgreSQL, MariaDB) and versions a new database can use, with the size options offered."}},"/databases/{namespace}/databases":{"get":{"summary":"List managed databases in a Project","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of managed databases","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseList"},"example":{"total":2,"items":[{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","engine":"postgresql","version":"1","phase":"Running","endpoint":"https://web.acme-web.kube-dc.example","externalEndpoint":"https://web.acme-web.kube-dc.example","replicas":2,"readyInstances":2,"instances":2,"cpu":"2","memory":"4Gi","storage":"20Gi","databaseName":"app","username":"jdoe","backupEnabled":true,"latestBackup":{},"exposeType":"expose-type","openBaoEngineConfigured":true,"conditions":[{}],"labels":{"app":"labels"},"createdAt":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z"}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"databases \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"databases\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getDatabasesDatabases","description":"The project's databases with engine, version, phase, endpoints and backup state."},"post":{"summary":"Create a new KdcDatabase","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseCreate"},"example":{"name":"orders","engine":"postgresql","version":"16","cpu":"1","memory":"2Gi","storage":"20Gi","replicas":2,"databaseName":"orders","username":"app","backup":{"enabled":true,"schedule":"0 2 * * *","retentionDays":7},"expose":{"type":"internal"}}}}},"responses":{"201":{"description":"Database created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseCreated"},"example":{"name":"web-1","namespace":"acme-web","message":"Done."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"databases \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"databases\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postDatabasesDatabases","description":"Creates a database from a KdcDatabase spec (engine, version, size, replicas, backup). The platform provisions it asynchronously; watch its phase."}},"/databases/{namespace}/databases/{name}":{"get":{"summary":"Get a specific KdcDatabase","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"responses":{"200":{"description":"Database details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseDetail"},"example":{"metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","labels":{"app":"labels"},"creationTimestamp":"2026-10-01T09:30:00Z"},"spec":{"backup":{"destinationPath":"images/","enabled":true,"encryption":{"enabled":false,"kmsKeyName":"web-1","postProcess":{"enabled":false,"image":"shalb/db-backup-encryptor:v0.1.0-placeholder","imagePullSecrets":[{"name":""}],"schedule":"30 2 * * *"},"wrappedDEKSecretName":"web-tls"},"retentionDays":7,"s3CredentialSecret":"web-tls","s3Endpoint":"https://web.acme-web.kube-dc.example","schedule":"0 2 * * *"},"cpu":"1","databaseName":"app","engine":"postgresql","expose":{"type":"internal"},"memory":"2Gi","parameters":{"web-1":"parameters"},"replicas":2,"restoreFrom":{"backupName":"web-1","sourceDatabaseName":"web-1","targetTime":"2026-10-01T09:30:00Z"},"storage":"20Gi","storageClassName":"local-path","username":"app","version":"16"},"status":{"backupDestinationPath":"images/","backupEncryption":{"kmsKeyId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","kmsKeyName":"web-1","lastWrappedAt":"2026-10-01T09:30:00Z","postProcessCronJobName":"web-1","wrappedDEKSecretName":"web-tls","wrappedDEKVersion":1},"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"endpoint":"https://web.acme-web.kube-dc.example","externalEndpoint":"https://web.acme-web.kube-dc.example","instances":2,"latestBackup":"2026-10-01T09:30:00Z","observedGeneration":1,"openBaoEngineConfigured":true,"phase":"Pending","readyInstances":2,"restore":{"backupName":"web-1","completedAt":"2026-10-01T09:30:00Z","message":"Done.","phase":"InProgress","sourceDatabaseName":"web-1","startedAt":"2026-10-01T09:30:00Z","targetTime":"2026-10-01T09:30:00Z"},"storageClassName":"local-path","storageUsed":"storage-used","version":"1"}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"databases \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"databases\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getDatabasesDatabasesByName","description":"One database's spec and status."},"delete":{"summary":"Delete a KdcDatabase","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"responses":{"200":{"description":"Database deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ClusterMessage"},"example":{"message":"Done."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"databases \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"databases\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteDatabasesDatabasesByName","description":"Deletes the database. Backups are kept unless `deleteBackups=true`."}},"/databases/{namespace}/databases/{name}/yaml":{"get":{"summary":"Get database YAML","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"responses":{"200":{"description":"Database YAML content","content":{"text/yaml":{"schema":{"type":"string"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"yaml \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"yaml\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getDatabasesDatabasesYaml","description":"The KdcDatabase manifest as YAML."}},"/databases/{namespace}/databases/{name}/events":{"get":{"summary":"Get events for a database","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"responses":{"200":{"description":"List of database events","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventList"},"example":{"items":[{}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"events \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"events\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getDatabasesDatabasesEvents","description":"Kubernetes events about the database, newest first."}},"/databases/{namespace}/databases/{name}/password":{"get":{"summary":"Get database admin password","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"responses":{"200":{"description":"Database credentials","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabasePassword"},"example":{"username":"jdoe","password":"<password>","databaseName":"app","engine":"postgresql"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"password \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"password\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getDatabasesDatabasesPassword","description":"The application user's name and password, read from the database's Secret. Treat the response as a secret."}},"/databases/{namespace}/databases/{name}/rotate-password":{"post":{"summary":"Rotate database password","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["app"],"description":"Only application-password rotation is supported."}}},"example":{"type":"app"}}}},"responses":{"200":{"description":"Application password rotated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MessageResult"},"example":{"success":true,"message":"Done."}}}},"410":{"description":"Root and superuser password rotation is retired"}},"operationId":"postDatabasesDatabasesRotatePassword","description":"Generates a new password for the application user and updates its Secret. Only `{ \"type\": \"app\" }` is accepted; superuser rotation is retired (410)."}},"/databases/{namespace}/databases/{name}/backup":{"patch":{"summary":"Update backup configuration for a database","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"enabled":{"type":"boolean"},"schedule":{"type":"string"},"retentionDays":{"type":"integer"}}},"example":{"enabled":true,"schedule":"0 3 * * *","retentionDays":14}}}},"responses":{"200":{"description":"Backup configuration updated","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseBackupConfig"},"example":{"success":true,"backup":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"backup \"web-1\" is forbidden: User \"jane@acme.example\" cannot patch resource \"backup\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"patchDatabasesDatabasesBackup","description":"Turns scheduled backups on or off. Body: `enabled`, `schedule` (cron) and `retentionDays`."}},"/databases/{namespace}/databases/{name}/backups":{"get":{"summary":"Get backup history for a database","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"responses":{"200":{"description":"List of backups with status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseBackupList"},"example":{"engine":"postgresql","backupConfig":{},"backupStatus":{},"destinationPath":"images/","backupReady":true,"items":[{"name":"web-1","type":"Physical","status":"Ready","createdAt":"2026-10-01T09:30:00Z"}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"backups \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"backups\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getDatabasesDatabasesBackups","description":"The database's backups, newest first, with their state."},"post":{"summary":"Trigger an on-demand backup for a database","tags":["Databases"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"responses":{"201":{"description":"Backup triggered","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BackupStarted"},"example":{"name":"web-1","engine":"postgresql"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"A required service is unavailable; retry later."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"backups \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"backups\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postDatabasesDatabasesBackups","description":"Starts a backup now, outside the schedule."}},"/databases/{namespace}/databases/{name}/snapshots":{"get":{"summary":"List restore-eligible snapshots (Backups) for a database","tags":["Databases"],"responses":{"200":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseSnapshotList"},"example":{"engine":"postgresql","pitrWindow":{},"archivingActive":true,"items":[{"name":"web-1","kind":"Backup","ready":true,"startedAt":"2026-10-01T09:30:00Z","completedAt":"2026-10-01T09:30:00Z","sizeBytes":1}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"snapshots \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"snapshots\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"operationId":"getDatabasesDatabasesSnapshots","description":"Backups that a restore can start from."}},"/databases/{namespace}/databases/{name}/restore":{"post":{"summary":"Trigger an in-place restore (destructive) from a snapshot","tags":["Databases"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["backupName"],"properties":{"backupName":{"type":"string"},"targetTime":{"type":"string","format":"date-time","description":"Point in time to recover to","within the backup window.":null}}},"example":{"backupName":"orders-20261002020000","targetTime":"2026-10-02T14:30:00Z"}}}},"responses":{"202":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoreStarted"},"example":{"database":"app","backupName":"web-1","targetTime":"2026-10-01T09:30:00Z"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"restore \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"restore\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"operationId":"postDatabasesDatabasesRestore","description":"Replaces the database's data with a backup, or with its state at a point in time. Body: `backupName`, or `targetTime`. Data written since is lost."}},"/databases/{namespace}/databases/{name}/restore-as-new":{"post":{"summary":"Create a new KdcDatabase that recovers from a snapshot","tags":["Databases"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["backupName","newName"],"properties":{"backupName":{"type":"string"},"newName":{"type":"string","pattern":"^[a-z0-9]([-a-z0-9]{0,52}[a-z0-9])?$","description":"Name of the new database."},"targetTime":{"type":"string","format":"date-time"}}},"example":{"backupName":"orders-20261002020000","newName":"orders-copy","targetTime":"2026-10-02T14:30:00Z"}}}},"responses":{"201":{"description":"OK","content":{"application/json":{"schema":{"$ref":"#/components/schemas/RestoredCopy"},"example":{"name":"web-1","sourceDatabaseName":"web-1","backupName":"web-1"}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"restore-as-new \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"restore-as-new\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"name":"name","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the database."}],"operationId":"postDatabasesDatabasesRestoreAsNew","description":"Creates a new database from a backup or point in time, leaving the original untouched. Body: `newName`, and `backupName` or `targetTime`."}},"/create-vm/{namespace}/vm-list":{"get":{"summary":"Get the list of VMs in a Project","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of VMs","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCreateVmVmList","description":"The project's VirtualMachines as a Kubernetes list."}},"/create-vm/{namespace}/vmi":{"post":{"summary":"Create a new VM","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"requestBody":{"required":true,"content":{"application/yaml":{"schema":{"type":"string"},"example":"apiVersion: kubevirt.io/v1\nkind: VirtualMachine\nmetadata:\n  name: web-1\n  namespace: acme-web\nspec:\n  runStrategy: Always\n  template:\n    spec:\n      networks:\n      - name: vpc_net_0\n        multus:\n          default: true\n          networkName: acme-web/default\n      domain:\n        cpu:\n          cores: 1\n        memory:\n          guest: 2Gi\n        devices:\n          interfaces:\n          - name: vpc_net_0\n            bridge: {}\n          disks:\n          - name: root-volume\n            disk:\n              bus: virtio\n      volumes:\n      - name: root-volume\n        dataVolume:\n          name: web-1-root\n"}}},"responses":{"201":{"description":"VM created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"409":{"description":"Conflicts with the current state; read it again and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Conflicts with the current state; read it again and retry."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"vmi \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"vmi\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postCreateVmVmi","description":"Creates a VM from a KubeVirt VirtualMachine manifest sent as YAML. GPU requests are checked against the project's quota and capacity first (see the validate endpoint). The root disk is created by the manifest's data volume templates."}},"/create-vm/{namespace}/vpclist":{"get":{"summary":"Get the VPC list for a Project","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of VPCs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ValueLabelOption"}},"example":[{"value":"value","label":"Web"}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCreateVmVpclist","description":"The VPCs the project's VMs can be connected to."}},"/create-vm/{namespace}/subnets/{vpc}":{"get":{"summary":"Get subnets for a VPC","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"vpc","required":true,"schema":{"type":"string"},"description":"Name of the VPC."}],"responses":{"200":{"description":"List of subnets","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ValueLabelOption"}},"example":[{"value":"value","label":"Web"}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCreateVmSubnetsByVpc","description":"Subnets of a VPC, for choosing a VM's network."}},"/create-vm/{namespace}/pvc/{name}":{"post":{"summary":"Create a PersistentVolumeClaim (used for the instant-clone VM root)","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the PersistentVolumeClaim to create."}],"requestBody":{"required":true,"content":{"application/yaml":{"schema":{"type":"string"},"example":"apiVersion: v1\nkind: PersistentVolumeClaim\nmetadata:\n  name: web-1-data\nspec:\n  accessModes: [ReadWriteOnce]\n  resources:\n    requests:\n      storage: 20Gi\n"}}},"responses":{"200":{"description":"PVC created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"400":{"description":"Invalid request; the message says which field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request; the message says which field."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}},"409":{"description":"Conflicts with the current state; read it again and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Conflicts with the current state; read it again and retry."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postCreateVmPvcByName","description":"Creates a PersistentVolumeClaim from a YAML manifest; the VM wizard uses it for a root disk cloned from a golden image."}},"/create-vm/{namespace}/storageclasses":{"get":{"summary":"Get available storage classes","description":"Storage classes with their tier, capabilities, supported access and volume modes, and which one is the default. With `purpose`, only the classes the storage capability contract offers for that use (VM root disk, managed database, backup bucket, ...).","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"query","name":"purpose","description":"Return only the classes suitable for this use (VM root disk, managed database, backup bucket, ...).","schema":{"type":"string","enum":["vm-root","vm-data","vm-migratable","volume","restore","k8s-worker-root","k8s-etcd","k8s-tenant-volumes","database","backup-bucket"]}},{"in":"query","name":"allowNodeLocal","description":"Also offer node-local classes where the purpose normally needs replicated storage (dev or single-instance plans).","schema":{"type":"boolean"}},{"in":"query","name":"production","description":"Refuse the capacity tier for latency-sensitive purposes such as production databases.","schema":{"type":"boolean"}},{"in":"query","name":"sourceProvisioner","description":"Driver of the volume being restored or cloned (purpose=restore).","schema":{"type":"string"}},{"in":"query","name":"sourceClass","description":"Class of the volume being restored or cloned (purpose=restore); its driver and pool are used, and the class itself stays offered.","schema":{"type":"string"}},{"in":"query","name":"sourcePool","description":"Pool of the volume being restored or cloned, as \"<cluster>/<pool>\" (purpose=restore).","schema":{"type":"string"}}],"responses":{"200":{"description":"List of storage classes","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/StorageClassOption"}},"example":[{"value":"ceph-block","label":"ceph-block","isDefault":false,"provisioner":"rook-ceph.rbd.csi.ceph.com","capabilities":[["ReadWriteOnce","Filesystem"],["ReadWriteOnce","Block"]]},{"value":"ceph-bucket","label":"ceph-bucket","isDefault":false,"provisioner":"rook-ceph.ceph.rook.io/bucket","capabilities":[["ReadWriteOnce","Filesystem"]]}]}}},"400":{"description":"Unknown storage purpose."},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCreateVmStorageclasses"}},"/create-vm/{namespace}/pvcs":{"get":{"summary":"Get available PVCs for VM creation","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of bound PVCs","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ValueLabelOption"}},"example":[{"value":"no-pvcs-available","label":"No PVCs available"}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCreateVmPvcs","description":"The project's PVCs that can be used as a VM disk."}},"/create-vm/{namespace}/datavolumelist":{"get":{"summary":"Get list of DataVolumes","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of DataVolumes","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesList"},"example":{"apiVersion":"v1","kind":"PodList","metadata":{"resourceVersion":"184702","continue":""},"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"An upstream service answered unexpectedly.","reason":"InternalError","code":502}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"datavolumelist \"web-1\" is forbidden: User \"jane@acme.example\" cannot get resource \"datavolumelist\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"getCreateVmDatavolumelist","description":"The project's DataVolumes as a Kubernetes list."}},"/create-vm/{namespace}/datavolume/{name}":{"post":{"summary":"Create a DataVolume","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the DataVolume."}],"requestBody":{"required":true,"content":{"application/yaml":{"schema":{"type":"string","description":"A CDI DataVolume manifest as YAML."},"example":"apiVersion: cdi.kubevirt.io/v1beta1\nkind: DataVolume\nmetadata:\n  name: web-1-root\nspec:\n  pvc:\n    accessModes: [ReadWriteOnce]\n    resources:\n      requests:\n        storage: 12Gi\n  source:\n    http:\n      url: https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img\n"}}},"responses":{"201":{"description":"DataVolume created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"409":{"description":"Conflicts with the current state; read it again and retry.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Conflicts with the current state; read it again and retry."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"postCreateVmDatavolumeByName","description":"Creates a DataVolume from a manifest, typically to import a disk image for a new VM."},"delete":{"summary":"Delete a DataVolume","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the DataVolume."},{"in":"query","name":"vm","schema":{"type":"string"},"description":"Virtual machine the volume is attached to; it is detached from it first."},{"in":"query","name":"is_pvc","schema":{"type":"boolean"},"description":"true when the volume is a PVC rather than a DataVolume."},{"in":"query","name":"is_detach_only","schema":{"type":"boolean"},"description":"true to detach the volume from its VM and keep it; otherwise it is deleted too."}],"responses":{"200":{"description":"DataVolume deleted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"502":{"description":"Kubernetes or another upstream service failed or answered unexpectedly.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"An upstream service answered unexpectedly.","reason":"InternalError","code":502}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"datavolume \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"datavolume\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteCreateVmDatavolumeByName","description":"Deletes a DataVolume and its data."}},"/create-vm/{namespace}/golden-images":{"get":{"summary":"List Ready golden images available for instant (CoW) cloning","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Array of Ready goldens (empty when none / feature absent). Each item: { osFamilyId, osName, snapshotName, storageClass, size, mode }. `mode` is 'Filesystem' (default RWO clone) or 'Block' (RWX-Block clone, the live-migratable root) — the UI offers the Migratable profile only when a Block golden exists for the selected OS AND a migration pool is non-empty.\n","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/GoldenImage"}},"example":[{"osFamilyId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","osName":"web-1","snapshotName":"web-1","storageClass":"local-path","size":"20Gi","mode":"Filesystem"}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCreateVmGoldenImages","description":"Ready golden images of the project's OS images, which make a VM root disk in seconds by copy-on-write cloning. Empty when the installation has none."}},"/create-vm/{namespace}/migration-pools":{"get":{"summary":"List live-migration-eligible node pools (>=2 CPU-compatible nodes)","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Array of pools ({cpuModel,vendor,count}); empty when none. Ordered deterministically — largest pool (count desc) first, then vendor, then cpuModel — so pools[0] is a stable \"primary\" pool the UI defaults to. On a multi-pool cluster the UI lets the user pick which pool to pin to.\n","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/MigrationPool"}},"example":[{"cpuModel":"Skylake-Client-IBRS","vendor":"Intel","count":3}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCreateVmMigrationPools","description":"Groups of nodes with the same CPU model. A VM can be live-migrated only within a pool of two or more nodes."}},"/create-vm/{namespace}/os-images":{"get":{"summary":"Get available OS images","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"List of OS images","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/OsImage"}},"example":[{"OS_NAME":"Ubuntu 26.04 LTS","CLOUD_USER":"ubuntu","OS_IMAGE_URL":"https://s3.kube-dc.example/cdi-os-images/ubuntu-26.04/baked/sha256/eceb7dad7619ecd1384c8420682e43d2bcd621176a493e3b028890de101b3a4e/image.qcow2","OS_IMAGE_UPSTREAM":"https://cloud-images.ubuntu.com/resolute/current/resolute-server-cloudimg-amd64.img","OS_IMAGE_SHA256":"eceb7dad7619ecd1384c8420682e43d2bcd621176a493e3b028890de101b3a4e","QGA_BAKED":true,"OS_IMAGE_BAKED_AT":"2026-09-06T07:16:31.415825+00:00","MIN_MEMORY":"1G","MIN_VCPU":"1","MIN_STORAGE":"20G","FIRMWARE_TYPE":"bios","MACHINE_TYPE":"q35","FEATURES":"acpi","BOOT_ORDER":"","ADDITIONAL_DISKS":"","CLOUD_INIT":"#cloud-config\npackage_update: false\npackage_upgrade: false\nruncmd:\n  - command -v qemu-ga >/dev/null 2>&1 || (apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends qemu-guest-agent)\n  - systemctl enable --now qemu-guest-agent\n","_versions":[{"displayName":"latest","imageURL":"https://s3.kube-dc.example/cdi-os-images/ubuntu/26.04/2026-09-13-8196be9d/resolute-server-cloudimg-amd64.img","isLatest":true,"sha256":"8196be9d7958059cb56c6c75c80fdf6cee8a8885bc149ea791d7db1c7ef93035","sizeBytes":863306240,"tag":"2026-09-13-8196be9d","uploadedAt":"2026-09-13T02:01:08Z","upstreamURL":"https://cloud-images.ubuntu.com/resolute/current/resolute-server-cloudimg-amd64.img"},{"displayName":"latest","imageURL":"https://s3.kube-dc.example/cdi-os-images/ubuntu/26.04/2026-09-08-8196be9d/resolute-server-cloudimg-amd64.img","isLatest":false,"sha256":"8196be9d7958059cb56c6c75c80fdf6cee8a8885bc149ea791d7db1c7ef93035","sizeBytes":863306240,"tag":"2026-09-08-8196be9d","uploadedAt":"2026-09-08T14:56:22Z","upstreamURL":"https://cloud-images.ubuntu.com/resolute/current/resolute-server-cloudimg-amd64.img"}],"_latestURL":"https://s3.kube-dc.example/cdi-os-images/ubuntu/26.04/latest/resolute-server-cloudimg-amd64.img","_familyId":"ubuntu-26.04"},{"OS_NAME":"Ubuntu 24.04 LTS","CLOUD_USER":"ubuntu","OS_IMAGE_URL":"https://s3.kube-dc.example/cdi-os-images/ubuntu-24.04/baked/sha256/6f86b95da529985da10b7696c73fcc11f984eed5fd3870e511705f7659b0faab/image.qcow2","OS_IMAGE_UPSTREAM":"https://cloud-images.ubuntu.com/server/releases/noble/release-20260911/ubuntu-24.04-server-cloudimg-amd64.img","OS_IMAGE_SHA256":"6f86b95da529985da10b7696c73fcc11f984eed5fd3870e511705f7659b0faab","QGA_BAKED":true,"OS_IMAGE_BAKED_AT":"2026-09-04T06:56:09.126917+00:00","MIN_MEMORY":"1G","MIN_VCPU":"1","MIN_STORAGE":"20G","FIRMWARE_TYPE":"bios","MACHINE_TYPE":"q35","FEATURES":"acpi","BOOT_ORDER":"","ADDITIONAL_DISKS":"","CLOUD_INIT":"#cloud-config\npackage_update: false\npackage_upgrade: false\nruncmd:\n  - command -v qemu-ga >/dev/null 2>&1 || (apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends qemu-guest-agent)\n  - systemctl enable --now qemu-guest-agent\n","_versions":[{"displayName":"ubuntu-noble-24.04-amd64-server-20260911","imageURL":"https://s3.kube-dc.example/cdi-os-images/ubuntu/24.04/20260911/noble-server-cloudimg-amd64.img","isLatest":true,"sha256":"612b2c0cc1bc413a6cb8c38fd611794caf0f2b436c50013d8b3794db12ad7354","sizeBytes":625256960,"tag":"20260911","uploadedAt":"2026-09-13T02:01:51Z","upstreamURL":"https://cloud-images.ubuntu.com/server/releases/noble/release-20260911/ubuntu-24.04-server-cloudimg-amd64.img"},{"displayName":"ubuntu-noble-24.04-amd64-server-20260814","imageURL":"https://s3.kube-dc.example/cdi-os-images/ubuntu/24.04/20260814/noble-server-cloudimg-amd64.img","isLatest":false,"sha256":"6e40c07ae715f744f84af0bec76415cc1987dd115b4b8de437818561f01a3733","sizeBytes":624447488,"tag":"20260814","uploadedAt":"2026-09-04T07:02:35Z","upstreamURL":"https://cloud-images.ubuntu.com/server/releases/noble/release-20260814/ubuntu-24.04-server-cloudimg-amd64.img"}],"_latestURL":"https://s3.kube-dc.example/cdi-os-images/ubuntu/24.04/latest/noble-server-cloudimg-amd64.img","_familyId":"ubuntu-24.04"}]}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}}},"operationId":"getCreateVmOsImages","description":"Operating system images the VM wizard offers, with their minimum size, firmware and versions."}},"/create-vm/{namespace}/attach/{name}":{"post":{"summary":"Attach disk to VM","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the disk (PVC or DataVolume) to attach."},{"in":"query","name":"vm","required":true,"schema":{"type":"string"},"description":"Virtual machine to add the disk to."}],"responses":{"200":{"description":"Disk attached","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"attach \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"attach\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postCreateVmAttachByName","description":"Adds a disk to a VM's definition. Query: `vm`, and `is_pvc` to attach a PVC instead of a DataVolume. Takes effect when the VM restarts; use the hotplug endpoint for a running VM."}},"/create-vm/{namespace}/detach/{name}":{"delete":{"summary":"Detach disk from VM","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the disk to detach."},{"in":"query","name":"vm","required":true,"schema":{"type":"string"},"description":"Virtual machine to remove the disk from."}],"responses":{"200":{"description":"Disk detached","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"detach \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"detach\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteCreateVmDetachByName","description":"Removes a disk from a VM's definition. Query: `vm`, `is_pvc`. Takes effect when the VM restarts. The volume and its data are kept."}},"/create-vm/{namespace}/detach-dv/{name}":{"delete":{"summary":"Detach DataVolume from VM (hotplug)","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the hot-plugged DataVolume."},{"in":"query","name":"vm","required":true,"schema":{"type":"string"},"description":"Running virtual machine to unplug the DataVolume from."}],"responses":{"200":{"description":"DataVolume detached","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"detach-dv \"web-1\" is forbidden: User \"jane@acme.example\" cannot delete resource \"detach-dv\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"deleteCreateVmDetachDvByName","description":"Unplugs a hot-plugged DataVolume from a running VM. Query: `vm`. The volume and its data are kept."}},"/create-vm/{namespace}/attach-dv/{name}":{"post":{"summary":"Attach DataVolume to VM (hotplug)","tags":["Virtual Machines"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"path","name":"name","required":true,"schema":{"type":"string"},"description":"Name of the DataVolume to hot-plug."},{"in":"query","name":"vm","required":true,"schema":{"type":"string"},"description":"Running virtual machine to hot-plug the DataVolume into."}],"responses":{"200":{"description":"DataVolume attached","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"default":{"description":"Kubernetes refused the request; its status code is passed through (403 when your role does not allow it, 404 when the object does not exist, 409 on a conflicting change).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"attach-dv \"web-1\" is forbidden: User \"jane@acme.example\" cannot create resource \"attach-dv\" in the namespace \"acme-web\"","reason":"Forbidden","code":403}}}}},"operationId":"postCreateVmAttachDvByName","description":"Hot-plugs a DataVolume into a running VM. Query: `vm`."}},"/billing/provider":{"get":{"summary":"Get billing provider for current organization","tags":["Billing"],"responses":{"200":{"description":"Billing provider information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingProviderInfo"},"example":{"success":true,"provider":"whmcs","organization":"acme","availableProviders":{"stripe":true,"whmcs":true},"mode":"whmcs"}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":false},"error":{"description":"A message, or an object with a machine-readable code and a message.","oneOf":[{"type":"string"},{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}}}]},"code":{"type":"string"}}},"example":{"success":false,"error":"Internal error.","code":"OK"}}}}},"operationId":"getBillingProvider","description":"Which payment provider is active for the organization (Stripe, WHMCS or none)."}},"/billing/projects":{"get":{"summary":"Get list of projects with billing data","tags":["Billing"],"responses":{"200":{"description":"List of projects with billing information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingProjectListResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"projects":["web"],"total_count":2,"filtered_count":2,"timestamp":"2026-10-01T09:30:00Z"}}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not signed in, or the session expired.","status":401,"message":"Not signed in, or the session expired."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"A required service is unavailable; retry later."}}}}},"operationId":"getBillingProjects","description":"Projects that have usage data for cost estimates."}},"/billing/project/{namespace}/overview":{"get":{"summary":"Get project billing overview","tags":["Billing"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."}],"responses":{"200":{"description":"Project billing overview","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingProjectOverviewResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"namespace":"acme-web","timestamp":"2026-10-01T09:30:00Z","billing_summary":{"billing_period":"billing_period","current_month_total":2,"last_day_spend":1,"total_cost_per_hour":12.5},"compute_instances":{"cost_per_hour":12.5,"cpu_cores":1,"memory_gib":1,"running_pods":1,"running_vms":1},"cost_breakdown":{"cpu_cost":12.5,"memory_cost":12.5,"storage_cost":12.5,"network_cost":12.5,"public_ip_cost":12.5},"resource_hours":{"cpu_hours":1,"memory_hours":1,"storage_hours_by_class":{"web-1":1}},"storage_and_network":{"cost_per_hour":12.5,"total_storage_gib":1,"storage_by_class":{"web-1":1}}}}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Not signed in, or the session expired.","status":401,"message":"Not signed in, or the session expired."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Your role does not allow this.","status":403,"message":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"A required service is unavailable; retry later.","status":503,"message":"A required service is unavailable; retry later."}}}}},"operationId":"getBillingProjectOverview","description":"Estimated costs of a project, by resource type, for the last day and the month so far, priced from usage metrics."}},"/billing/project/{namespace}/trends":{"get":{"summary":"Get project cost trends","tags":["Billing"],"parameters":[{"in":"path","name":"namespace","required":true,"schema":{"type":"string"},"description":"Project namespace, `<organization>-<project>` (for example `acme-web`)."},{"in":"query","name":"days","schema":{"type":"integer","default":30},"description":"Number of days to look back"}],"responses":{"200":{"description":"Project cost trends","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BillingProjectTrends"},"example":{"namespace":"acme-web","period_days":1,"start_date":"start_date","end_date":"end_date","total_snapshots":1,"trends":[{}]}}}},"401":{"description":"Not signed in, or the session expired.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not signed in, or the session expired."}}}},"403":{"description":"Your role does not allow this.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"A required service is unavailable; retry later."}}}}},"operationId":"getBillingProjectTrends","description":"The project's estimated cost over time."}},"/billing/pricing/{pricingModel}":{"get":{"summary":"Get pricing model information","tags":["Billing"],"parameters":[{"in":"path","name":"pricingModel","required":true,"description":"Pricing model to describe. The backend also answers GET /billing/pricing for the default model.","schema":{"type":"string"}}],"responses":{"200":{"description":"Pricing model information","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PricingModel"},"example":{}}}},"500":{"description":"Internal error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Internal error."}}}},"503":{"description":"A required service is unavailable; retry later.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"A required service is unavailable; retry later."}}}}},"operationId":"getBillingPricingByPricingModel","description":"Unit prices of a pricing model, used for the cost estimates."}},"/billing/whmcs-module":{"get":{"summary":"Download the Kube-DC WHMCS provisioning module (zip)","description":"Builds and serves the WHMCS module that operators install into their WHMCS server to wire it up to this cluster. The archive is zipped on the fly from the vendored source (ui/backend/whmcs-module, synced from integration/whmcs via integration/whmcs/sync-to-backend.sh) so it always reflects the source in this build. It contains plain PHP and the install README — no secrets — so it is served publicly.\n","tags":["Billing"],"responses":{"200":{"description":"WHMCS module archive","content":{"application/zip":{"schema":{"type":"string","format":"binary"}}}},"404":{"description":"Module source not bundled in this backend build"}},"operationId":"getBillingWhmcsModule"}},"/create-vm/{namespace}/vmi/validate":{"post":{"summary":"Validate a VM manifest","description":"Runs the GPU preflight checks on a VirtualMachine manifest without creating anything. VM creation repeats the same checks.","tags":["Virtual Machines"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"requestBody":{"required":true,"content":{"application/yaml":{"schema":{"type":"string","description":"KubeVirt VirtualMachine manifest."},"example":"apiVersion: kubevirt.io/v1\nkind: VirtualMachine\nmetadata:\n  name: web-1\n  namespace: acme-web\nspec:\n  runStrategy: Always\n  template:\n    spec:\n      networks:\n      - name: vpc_net_0\n        multus:\n          default: true\n          networkName: acme-web/default\n      domain:\n        cpu:\n          cores: 1\n        memory:\n          guest: 2Gi\n        devices:\n          interfaces:\n          - name: vpc_net_0\n            bridge: {}\n          disks:\n          - name: root-volume\n            disk:\n              bus: virtio\n      volumes:\n      - name: root-volume\n        dataVolume:\n          name: web-1-root\n"}}},"responses":{"200":{"description":"The manifest passed validation.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean","const":true},"data":{"type":"object"}}},"example":{"success":true,"data":{}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"503":{"description":"GPU validation is temporarily unavailable."}},"operationId":"postCreateVmVmiValidate"}},"/create-vm/{namespace}/vmi/{name}":{"delete":{"summary":"Delete a VM","tags":["Virtual Machines"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"responses":{"200":{"description":"Kubernetes delete status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"deleteCreateVmVmiByName","description":"Deletes the VM. Disks created by its data volume templates are deleted with it; separately created volumes are kept."}},"/create-vm/{namespace}/datavolume/{name}/progress":{"get":{"summary":"Get disk import progress","description":"Import progress of a VM root disk, estimated from the DataVolume status, events and importer logs.","tags":["Virtual Machines"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/VolumeName"}],"responses":{"200":{"description":"Progress.","content":{"application/json":{"schema":{"type":"object","properties":{"progress":{"type":"integer","minimum":0,"maximum":100},"status":{"type":"object","properties":{"phase":{"type":"string","example":"ImportInProgress"},"message":{"type":"string"},"type":{"type":"string","enum":["info","success","warning","error"]}}},"dataVolume":{"$ref":"#/components/schemas/KubernetesResource"},"pvc":{"$ref":"#/components/schemas/KubernetesResource"},"events":{"$ref":"#/components/schemas/KubernetesResource"},"importerPodLogs":{"type":"string"}}},"example":{"progress":1,"status":{"phase":"ImportInProgress","message":"Done.","type":"info"},"dataVolume":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"pvc":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"events":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"importerPodLogs":"importer-pod-logs"}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getCreateVmDatavolumeProgress"}},"/create-vm/{namespace}/clone-pvc/{name}":{"post":{"summary":"Clone a volume as a PVC","tags":["Volumes"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/VolumeName"},{"$ref":"#/components/parameters/CloneSource"},{"$ref":"#/components/parameters/CloneStorageClass"},{"$ref":"#/components/parameters/VolumeSize"}],"responses":{"200":{"description":"Clone requested.","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"postCreateVmClonePvcByName","description":"Creates a PVC as a copy of another (query: `source`), with the given storage class and size."}},"/create-vm/{namespace}/clone-dv/{name}":{"post":{"summary":"Clone a volume as a DataVolume","tags":["Volumes"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/VolumeName"},{"$ref":"#/components/parameters/CloneSource"},{"$ref":"#/components/parameters/CloneStorageClass"},{"$ref":"#/components/parameters/VolumeSize"}],"responses":{"200":{"description":"Clone requested.","content":{"text/plain":{"schema":{"type":"string","example":"OK"}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"postCreateVmCloneDvByName","description":"Creates a DataVolume as a copy of a PVC (query: `source`), with the given storage class and size."}},"/create-vm/{namespace}/resize-pvc/{name}":{"patch":{"summary":"Expand a volume","description":"Volumes can only grow.","tags":["Volumes"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/VolumeName"},{"$ref":"#/components/parameters/VolumeSize"}],"responses":{"200":{"description":"Updated PVC.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"400":{"description":"Missing size, or the new size is not larger than the current one.","content":{"text/plain":{"schema":{"type":"string"},"example":"Missing size, or the new size is not larger than the current one."}}}},"operationId":"patchCreateVmResizePvcByName"}},"/create-vm/{namespace}/delete-dv/{name}":{"delete":{"summary":"Delete a DataVolume","tags":["Volumes"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/VolumeName"}],"responses":{"200":{"description":"Kubernetes' answer to the delete.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"deleteCreateVmDeleteDvByName","description":"Deletes a DataVolume and its data."}},"/create-vm/{namespace}/delete-pvc/{name}":{"delete":{"summary":"Delete a PVC","tags":["Volumes"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/VolumeName"}],"responses":{"200":{"description":"Kubernetes' answer to the delete.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"deleteCreateVmDeletePvcByName","description":"Deletes a PVC and its data."}},"/secrets/{namespace}":{"get":{"summary":"List secrets","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Secrets in the project (metadata only).","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ManagedSecretSummary"}}}},"example":{"items":[{"name":"payments-api","namespace":"acme-web","creationTimestamp":"2026-10-03T00:58:14Z","type":"opaque","description":"api contract","sync":{"enabled":true,"targetSecretName":"payments-api","refreshInterval":"1h","keys":[]},"rotation":{},"status":{"conditions":[{"lastTransitionTime":"2026-10-03T00:58:14Z","message":"spec.rotation.enabled=false","reason":"RotationDisabled","status":"False","type":"RotationScheduled"},{"lastTransitionTime":"2026-10-03T00:58:14Z","message":"","reason":"Synced","status":"True","type":"Synced"}],"syncedSecretName":"payments-api"}}]}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getSecretsByNamespace","description":"The project's managed secrets, without their values."}},"/secrets/{namespace}/{name}":{"get":{"summary":"Get a secret","description":"Returns metadata. With `includeValue=true` also returns the current values; reading values is audited.","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"},{"name":"includeValue","in":"query","schema":{"type":"boolean","default":false},"description":"true to include the secret's current values; reading them is audited."}],"responses":{"200":{"description":"The secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedSecretSummary"},"example":{"name":"payments-api","namespace":"acme-web","creationTimestamp":"2026-10-03T00:58:14Z","type":"opaque","description":"api contract","sync":{"enabled":true,"targetSecretName":"payments-api","refreshInterval":"1h","keys":[]},"rotation":{},"status":{"conditions":[]},"openbao":{"currentVersion":1,"createdTime":"2026-10-03T00:58:14.550204929Z","updatedTime":"2026-10-03T00:58:14.550204929Z","maxVersions":0,"casRequired":false,"customMetadata":{}},"value":{"data":{"a":"1"},"metadata":{"version":1,"createdTime":"2026-10-03T00:58:14.550204929Z","customMetadata":{"kube-dc.com/description":"api contract","kube-dc.com/type":"opaque"}}}}}}},"403":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getSecretsByName"},"post":{"summary":"Create a secret","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"}],"requestBody":{"content":{"application/json":{"schema":{"type":"object","properties":{"type":{"type":"string","enum":["opaque","password","api-key","tls","db-static"],"default":"opaque"},"description":{"type":"string"},"sync":{"$ref":"#/components/schemas/SecretSync"},"initialValues":{"allOf":[{"$ref":"#/components/schemas/SecretValues"}],"description":"Optional first version. Without it the secret starts empty."}}},"example":{"type":"api-key","description":"Payment provider API key","sync":{"enabled":true,"targetSecretName":"payments-api"},"initialValues":{"API_KEY":"sk_test_4eC39HqLyjWDarjtT1zdp7dc"}}}}},"responses":{"200":{"description":"Secret created.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ManagedSecretSummary"},{"type":"object","properties":{"kvVersion":{"type":"integer","description":"Version written from `initialValues`","if any.":null}}}]},"example":{"name":"payments-api","namespace":"acme-web","creationTimestamp":"2026-10-03T00:58:14Z","type":"opaque","description":"api contract","sync":{"enabled":true,"targetSecretName":"payments-api","refreshInterval":"1h","keys":[]},"rotation":{"enabled":false},"status":{"conditions":[]},"kvVersion":1}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postSecretsByName","description":"Creates a managed secret, optionally with its first values and a Kubernetes Secret to sync to."},"delete":{"summary":"Delete a secret","description":"Soft-deletes by default; versions stay recoverable in OpenBao. `destroy=true` removes all versions irreversibly.","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"},{"name":"destroy","in":"query","schema":{"type":"boolean","default":false},"description":"true to remove every version irreversibly instead of a recoverable soft delete."}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/DeleteResult"},{"type":"object","properties":{"destroyed":{"type":"boolean"}}}]},"example":{"name":"payments-api","namespace":"acme-web","deleted":true,"destroyed":true}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"deleteSecretsByName"}},"/secrets/{namespace}/{name}/values":{"put":{"summary":"Write secret values","description":"Writes a new version containing exactly the given keys.","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/SecretValues"}}},"example":{"data":{"API_KEY":"sk_test_51HqLyjWDarjtT1zdp7dc4eC39"}}}}},"responses":{"200":{"description":"New version written.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"mount":{"type":"string"},"version":{"type":"integer"},"createdTime":{"type":"string","format":"date-time"}}},"example":{"name":"payments-api","namespace":"acme-web","mount":"kv-web","version":2,"createdTime":"2026-10-03T00:58:14.79141016Z"}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"putSecretsValues"}},"/secrets/{namespace}/{name}/sync":{"post":{"summary":"Configure Kubernetes Secret sync","description":"Updates only the fields present in the body.","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SecretSync"},"example":{"enabled":true,"targetSecretName":"payments-api","refreshInterval":"1h","keys":["API_KEY"]}}}},"responses":{"200":{"description":"Updated secret.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedSecretSummary"},"example":{"name":"payments-api","namespace":"acme-web","creationTimestamp":"2026-10-03T00:58:14Z","type":"opaque","description":"api contract","sync":{"enabled":true,"targetSecretName":"payments-api","refreshInterval":"1h","keys":[]},"rotation":{},"status":{"conditions":[{"lastTransitionTime":"2026-10-03T00:58:14Z","message":"spec.rotation.enabled=false","reason":"RotationDisabled","status":"False","type":"RotationScheduled"},{"lastTransitionTime":"2026-10-03T00:58:14Z","message":"","reason":"Synced","status":"True","type":"Synced"}],"syncedSecretName":"payments-api"}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postSecretsSync"}},"/secrets/{namespace}/{name}/import":{"post":{"summary":"Import an existing Kubernetes Secret","description":"Copies a Secret's data into a new managed secret. Cross-namespace import needs `allowCrossNamespace`.","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sourceSecretName"],"properties":{"sourceSecretName":{"type":"string"},"sourceSecretNamespace":{"type":"string","description":"Defaults to the target namespace."},"allowCrossNamespace":{"type":"boolean"},"type":{"type":"string","default":"opaque"},"description":{"type":"string"},"sync":{"$ref":"#/components/schemas/SecretSync"}}},"example":{"sourceSecretName":"payments-api-legacy","type":"api-key","description":"Imported from the legacy Kubernetes Secret","sync":{"enabled":true,"targetSecretName":"payments-api"}}}}},"responses":{"200":{"description":"Secret imported.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ManagedSecretSummary"},{"type":"object","properties":{"kvVersion":{"type":"integer"},"importedFrom":{"type":"object","properties":{"namespace":{"type":"string"},"name":{"type":"string"},"keys":{"type":"array","items":{"type":"string"}}}}}}]},"example":{"name":"web-1","namespace":"acme-web","creationTimestamp":"2026-10-01T09:30:00Z","type":"opaque","description":"Acme web shop","sync":{"enabled":true,"targetSecretName":"web-tls","refreshInterval":"1h","keys":["images/logo.png"]},"rotation":{},"publicationRef":{},"readOnly":true,"status":{"conditions":[{}],"syncedSecretName":"web-tls"},"openbao":{"currentVersion":1,"createdTime":"2026-10-01T09:30:00Z","updatedTime":"2026-10-01T09:30:00Z","maxVersions":1,"casRequired":true,"customMetadata":{"API_URL":"custom-metadata"}},"value":{"data":{"username":"app","password":"s3cr3t"},"metadata":{"version":1}},"valueMissing":true,"kvVersion":1,"importedFrom":{"namespace":"acme-web","name":"web-1","keys":["images/logo.png"]}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postSecretsImport"}},"/secrets/{namespace}/{name}/consumers":{"get":{"summary":"List workloads using a secret","description":"Scans project workloads for references to the synced Kubernetes Secret. Per-kind scan failures are reported in `errors` without failing the request.","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"}],"responses":{"200":{"description":"Consumers.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object"}},"secret":{"type":"string"},"scannerVersion":{"type":"string"},"cached":{"type":"boolean"},"errors":{"type":"array","items":{"type":"object"}}}},"example":{"items":[{}],"secret":"secret","scannerVersion":"1","cached":true,"errors":[{}]}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getSecretsConsumers"}},"/secrets/{namespace}/{name}/versions/{version}/destroy":{"post":{"summary":"Destroy a secret version","description":"Irreversibly removes one version's data.","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"},{"name":"version","in":"path","required":true,"schema":{"type":"integer","minimum":1},"description":"KV version number to destroy."}],"responses":{"200":{"description":"Version destroyed.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"destroyedVersion":{"type":"integer"}}},"example":{"name":"payments-api","namespace":"acme-web","destroyedVersion":1}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postSecretsVersionsDestroy"}},"/secrets/{namespace}/{name}/yaml":{"get":{"summary":"Get secret YAML","description":"The ManagedSecret manifest. Contains no secret values.","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"}],"responses":{"200":{"$ref":"#/components/responses/ResourceYaml"},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getSecretsYaml"},"put":{"summary":"Replace secret YAML","tags":["Secrets"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/SecretName"}],"requestBody":{"required":true,"description":"Full resource manifest. Replaces the stored object.","content":{"application/yaml":{"schema":{"type":"string"},"example":"apiVersion: security.kube-dc.com/v1alpha1\nkind: ManagedSecret\nmetadata:\n  name: payments-api\n  namespace: acme-web\n  resourceVersion: \"184851\"\nspec:\n  type: api-key\n  description: Payment provider API key\n  sync:\n    enabled: true\n    targetSecretName: payments-api\n"}}},"responses":{"200":{"description":"Updated object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedSecret"},"example":{"apiVersion":"security.kube-dc.com/v1alpha1","kind":"ManagedSecret","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"description":"Acme web shop","publicationRef":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"},"rotation":{"enabled":true,"generator":{"charset":"alnum-symbol","length":32},"interval":"30d"},"sync":{"enabled":false,"keys":["images/logo.png"],"refreshInterval":"1h","targetSecretName":"web-tls"},"type":"opaque"},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"currentVersion":1,"lastRotatedTime":"2026-10-01T09:30:00Z","lastSyncedTime":"2026-10-01T09:30:00Z","nextRotationTime":"2026-10-01T09:30:00Z","syncedSecretName":"web-tls"}}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"putSecretsYaml","description":"Replaces the ManagedSecret manifest. This changes its settings (type, sync, rotation), never its values."}},"/platform/info":{"get":{"summary":"Get platform information","tags":["Platform"],"security":[],"responses":{"200":{"description":"Installation metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"version":{"type":["string","null"],"description":"Backend version."},"supportUrl":{"type":"string","format":"uri"},"documentationUrl":{"type":"string","format":"uri"},"apiReferenceUrl":{"type":["string","null"],"format":"uri","description":"Where this API reference is served; open it with ?org=&project= to pre-fill requests."}}},"example":{"version":"v0.9.1-1790988198","supportUrl":"https://support.kube-dc.example","documentationUrl":"https://docs.kube-dc.com/cloud","apiReferenceUrl":"https://backend.kube-dc.example/"}}}}},"operationId":"getPlatformInfo","description":"The backend version and the installation's support, documentation and API reference links. Public."}},"/public/branding":{"get":{"summary":"Get branding","description":"Product name, colors and logo URLs for this installation. Never fails; returns stock defaults if branding cannot be read.","tags":["Platform"],"security":[],"responses":{"200":{"description":"Branding.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PublicBranding"},"example":{"productName":"Cloud Acropolis","productTagline":"Console Whitelabel","logoUrl":null,"logoDarkUrl":null,"loginLogoUrl":null,"faviconUrl":null,"colors":{"primary":"#002952","accent":"#40199a"},"colorMode":"custom","logoIncludesName":false,"disabledSections":[],"schemaVersion":1,"resolutionState":"ready","rev":"149f18444b99"}}}}},"operationId":"getPublicBranding"}},"/public/branding/logo.png":{"get":{"summary":"Get the logo","tags":["Platform"],"security":[],"responses":{"200":{"$ref":"#/components/responses/BrandingImage"}},"operationId":"getPublicBrandingLogoPng","description":"The installation's logo. Public, so login pages can show it."}},"/public/branding/logo-dark.png":{"get":{"summary":"Get the dark-mode logo","tags":["Platform"],"security":[],"responses":{"200":{"$ref":"#/components/responses/BrandingImage"}},"operationId":"getPublicBrandingLogoDarkPng","description":"The installation's logo for dark backgrounds. Public."}},"/public/branding/login-logo.png":{"get":{"summary":"Get the login page logo","tags":["Platform"],"security":[],"responses":{"200":{"$ref":"#/components/responses/BrandingImage"}},"operationId":"getPublicBrandingLoginLogoPng","description":"The logo shown on the login page. Public."}},"/public/branding/favicon.png":{"get":{"summary":"Get the favicon","tags":["Platform"],"security":[],"responses":{"200":{"$ref":"#/components/responses/BrandingImage"}},"operationId":"getPublicBrandingFaviconPng","description":"The installation's favicon. Public."}},"/register/options":{"get":{"summary":"Get registration options","description":"Whether new organizations can sign up for pay-as-you-go.","tags":["Registration"],"security":[],"responses":{"200":{"description":"Options.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"payg":{"type":"object","properties":{"available":{"type":"boolean"},"reason":{"type":"string"},"collectionMode":{"type":"string","description":"`shadow` measures usage without charging."}}}}},"example":{"success":true,"payg":{"available":false,"reason":"disabled"}}}}}},"operationId":"getRegisterOptions"}},"/register/my-organizations":{"get":{"summary":"List my organizations","description":"Organizations the signed-in user already belongs to, so a returning user can be sent to the right one. Takes a token from the self-service sign-up realm.","tags":["Registration"],"responses":{"200":{"description":"Organizations.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"cached":{"type":"boolean"},"organizations":{"type":"array","items":{"type":"object"}},"partial":{"type":"boolean","description":"Some organizations could not be searched."}}},"example":{"success":true,"cached":true,"organizations":[{}],"partial":true}}}},"401":{"description":"Not signed in."},"503":{"description":"Lookup is temporarily unavailable."}},"operationId":"getRegisterMyOrganizations"}},"/databases/{namespace}/permissions":{"get":{"summary":"Get database permissions","description":"Which database actions the caller may perform in the project.","tags":["Databases"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"One flag per action.","content":{"application/json":{"schema":{"type":"object","properties":{"rotate":{"type":"boolean"},"create":{"type":"boolean"},"patch":{"type":"boolean"},"delete":{"type":"boolean"},"backupPostgres":{"type":"boolean"},"backupMaria":{"type":"boolean"}}},"example":{"rotate":true,"create":true,"patch":true,"delete":true,"backupPostgres":true,"backupMaria":true}}}},"400":{"description":"Invalid namespace."}},"operationId":"getDatabasesPermissions"}},"/databases/{namespace}/databases/{name}/console-delete":{"post":{"summary":"Delete a database","description":"Deletes the database only if its UID still matches, so a database recreated under the same name is never deleted by mistake. Backups are kept.","tags":["Databases"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["uid","confirmation"],"properties":{"uid":{"type":"string"},"confirmation":{"type":"string","description":"The database name","typed to confirm.":null}}},"example":{"uid":"9d0e1f2a-3b4c-4d5e-8f6a-7b8c9d0e1f2a","confirmation":"orders"}}}},"responses":{"200":{"description":"Deletion requested.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}},"example":{"message":"Done."}}}},"400":{"description":"Missing or wrong confirmation."},"409":{"description":"The database was replaced since it was read."}},"operationId":"postDatabasesDatabasesConsoleDelete"}},"/manage-organization/settings":{"get":{"summary":"Get organization settings","tags":["Organization"],"responses":{"200":{"description":"Settings.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrgSettings"},"organization":{"type":"string"}}}]},"example":{"success":true,"data":{"name":"acme","description":"Created via WHMCS order","email":"jane@acme.example"},"timestamp":"2026-10-03T00:57:51.237Z","organization":"acme"}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getManageOrganizationSettings","description":"The organization's display description and contact email."},"put":{"summary":"Update organization settings","tags":["Organization"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string"},"email":{"type":"string","format":"email"}}},"example":{"description":"Acme web shop","email":"ops@acme.example"}}}},"responses":{"200":{"description":"Updated settings.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/OrgSettings"},"organization":{"type":"string"}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"name":"web-1","description":"Acme web shop","email":"jane@acme.example"},"organization":"acme"}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"putManageOrganizationSettings","description":"Updates the organization's description and contact email. Requires org-admin."}},"/manage-organization/session-policy":{"get":{"summary":"Get session policy","description":"How long console sessions in the organization last.","tags":["Organization"],"responses":{"200":{"description":"Policy.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SessionPolicy"}}},"example":{"success":true,"data":{"idleSeconds":1800,"maxSeconds":36000,"clientIdleSeconds":0,"clientMaxSeconds":0,"canManage":true}}}}},"401":{"description":"Not signed in."},"503":{"description":"Session settings are temporarily unavailable."}},"operationId":"getManageOrganizationSessionPolicy"},"put":{"summary":"Update session policy","description":"Requires org-admin. Both values must be between 15 minutes and 30 days, and `idleSeconds` cannot exceed `maxSeconds`.","tags":["Organization"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["idleSeconds","maxSeconds"],"additionalProperties":false,"properties":{"idleSeconds":{"type":"integer","minimum":900,"maximum":2592000},"maxSeconds":{"type":"integer","minimum":900,"maximum":2592000}}},"example":{"idleSeconds":3600,"maxSeconds":43200}}}},"responses":{"200":{"description":"Updated policy.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"$ref":"#/components/schemas/SessionPolicy"}}},"example":{"success":true,"data":{"idleSeconds":3600,"maxSeconds":3600,"clientIdleSeconds":3600,"clientMaxSeconds":3600,"canManage":true}}}}},"400":{"description":"Invalid durations."},"403":{"description":"Caller is not an org-admin."},"503":{"description":"The change could not be confirmed."}},"operationId":"putManageOrganizationSessionPolicy"}},"/manage-organization/projects/{projectId}/users":{"get":{"summary":"List project members","tags":["Organization"],"parameters":[{"name":"projectId","in":"path","required":true,"description":"Project name.","schema":{"type":"string"}}],"responses":{"200":{"description":"Members and their project roles.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"email":{"type":"string"},"username":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"status":{"type":"string","enum":["Active","Inactive"]},"joinedAt":{"type":"string","format":"date-time"}}}},"total":{"type":"integer"},"projectId":{"type":"string"},"projectGroups":{"type":"array","items":{"type":"string"}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":[{"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","name":"web-1","email":"jane@acme.example","username":"jdoe","roles":["developer"],"status":"Active","joinedAt":"2026-10-01T09:30:00Z"}],"total":2,"projectId":"web","projectGroups":["project-group"]}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getManageOrganizationProjectsUsers","description":"Members of a project and the roles they hold in it, resolved from the organization's groups."}},"/manage-organization/roles/{roleName}/manifest":{"get":{"summary":"Get a project role manifest","description":"The Kubernetes Role behind a project role. Requires org-admin.","tags":["Organization"],"parameters":[{"name":"roleName","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the project role."},{"name":"projectId","in":"query","required":true,"description":"Project name.","schema":{"type":"string"}}],"responses":{"200":{"description":"The Role.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/KubernetesResource"}}}]},"example":{"success":true,"data":{"kind":"Role","apiVersion":"rbac.authorization.k8s.io/v1","metadata":{"name":"deployer","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-000000000007","resourceVersion":"660490764","creationTimestamp":"2026-10-03T00:58:29Z"},"rules":[{"verbs":["get"],"apiGroups":[""],"resources":["configmaps"]}]},"timestamp":"2026-10-03T00:58:29.274Z"}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getManageOrganizationRolesManifest"}},"/network/{namespace}/vm-addresses":{"get":{"summary":"Get VM address options for a Project","description":"Returns the primary VPC and datacenter VLANs assigned to the Project's\ncurrent namespace and Project identities. The caller must have permission\nto list VMs in that namespace before the backend reads address metadata.\nForeign Project grants and subnets are excluded.\n\nA chosen IPv4 address requires a ready Kube-OVN network and a bridged VM\ninterface. Put the address in the VM template annotation\n`<provider>.kubernetes.io/ip_address`; omit it for automatic allocation.\nVM validation and creation repeat the address check before writes. Gateway,\nsubnet, broadcast, excluded, delegated, and allocated addresses are refused.\nKube-OVN owns final allocation, so a concurrent allocation can still prevent\nthe VM from starting. External DHCP interfaces use automatic allocation.\n","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Project interface address options. This response is not cached.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/VMAddressNetworkList"},"example":{"items":[{"name":"web-1","nadName":"web-1","provider":"provider","cidrBlock":"cidr-block","gateway":"gateway","excludeIps":["10.0.10.15"],"unavailableRanges":["unavailable-range"],"suggestedAddresses":["10.0.10.15"],"ready":true,"staticIPSupported":true,"reason":"Ready"}]}}}},"401":{"description":"Authentication is required."},"403":{"description":"The caller cannot list VMs in this Project."},"409":{"description":"Project network identity is not ready."},"502":{"description":"Address metadata or authorization is unavailable."}},"operationId":"getNetworkVmAddresses"}},"/network/{namespace}/fips/{name}":{"get":{"summary":"Get a Floating IP","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"responses":{"200":{"description":"The FIp object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FIp"},"example":{"apiVersion":"kube-dc.com/v1","kind":"FIp","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"allowedCIDRs":["10.0.10.0/24"],"eip":"web-ip","externalNetworkType":"public","ipAddress":"10.0.10.15","vmTarget":{"interfaceName":"web-1","vmName":"web-1"}},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"eip":"web-ip","externalIP":"10.0.10.15","ovnFip":"ovn-fip","ready":false,"resolvedTargetIP":"10.0.10.15","sourcePolicyRevision":"7","sourcePolicySpecHash":"source-policy-spec-hash","targetVMInterface":{"interfaceName":"web-1","ipAddress":"10.0.10.15","mac":"mac","vmName":"web-1"}}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"getNetworkFipsByName","description":"One Floating IP with its public address and target."},"put":{"summary":"Replace a Floating IP","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"requestBody":{"required":true,"description":"Full `kube-dc.com/v1` FIp object, including `metadata.resourceVersion`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FIp"},"example":{"apiVersion":"kube-dc.com/v1","kind":"FIp","metadata":{"name":"web-public","resourceVersion":"184730"},"spec":{"externalNetworkType":"public","ipAddress":"10.0.10.15","allowedCIDRs":["203.0.113.0/24"]}}}}},"responses":{"200":{"description":"Updated FIp.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/FIp"},"example":{"apiVersion":"kube-dc.com/v1","kind":"FIp","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"allowedCIDRs":["10.0.10.0/24"],"eip":"web-ip","externalNetworkType":"public","ipAddress":"10.0.10.15","vmTarget":{"interfaceName":"web-1","vmName":"web-1"}},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"eip":"web-ip","externalIP":"10.0.10.15","ovnFip":"ovn-fip","ready":false,"resolvedTargetIP":"10.0.10.15","sourcePolicyRevision":"7","sourcePolicySpecHash":"source-policy-spec-hash","targetVMInterface":{"interfaceName":"web-1","ipAddress":"10.0.10.15","mac":"mac","vmName":"web-1"}}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"putNetworkFipsByName","description":"Replaces the Floating IP with the object in the body; use it to point the address at another VM. Include metadata.resourceVersion from the last read."},"delete":{"summary":"Delete a Floating IP","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"responses":{"200":{"description":"Deleted.","content":{"text/plain":{"schema":{"type":"string"}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"deleteNetworkFipsByName","description":"Deletes the Floating IP; the VM keeps its private address."}},"/network/{namespace}/load-balancers":{"get":{"summary":"List LoadBalancer services","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Services of type LoadBalancer.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/KubernetesResource"}}}},"example":{"items":[{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}]}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"getNetworkLoadBalancers","description":"The project's Services of type LoadBalancer."},"post":{"summary":"Create a LoadBalancer service","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"requestBody":{"required":true,"description":"A Kubernetes Service with `spec.type: LoadBalancer`.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Service","metadata":{"name":"web-lb","annotations":{"service.nlb.kube-dc.com/bind-on-default-gw-eip":"true"}},"spec":{"type":"LoadBalancer","selector":{"app":"web"},"ports":[{"name":"http","port":80,"targetPort":8080,"protocol":"TCP"}]}}}}},"responses":{"200":{"description":"Created Service.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"postNetworkLoadBalancers","description":"Creates a Service of type LoadBalancer; the platform gives it an External IP."}},"/network/{namespace}/load-balancers/{name}":{"get":{"summary":"Get a LoadBalancer service","description":"The Service with its Endpoints and recent events.","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"responses":{"200":{"description":"Service details.","content":{"application/json":{"schema":{"type":"object","properties":{"service":{"$ref":"#/components/schemas/KubernetesResource"},"endpoints":{"$ref":"#/components/schemas/KubernetesResource"},"events":{"$ref":"#/components/schemas/KubernetesResource"}}},"example":{"service":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"endpoints":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}},"events":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"getNetworkLoadBalancersByName"},"put":{"summary":"Replace a LoadBalancer service","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Service","metadata":{"name":"web-lb","resourceVersion":"184744","annotations":{"service.nlb.kube-dc.com/expose-route":"https"}},"spec":{"type":"LoadBalancer","selector":{"app":"web"},"ports":[{"name":"https","port":443,"targetPort":8443,"protocol":"TCP"}]}}}}},"responses":{"200":{"description":"Updated Service.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"putNetworkLoadBalancersByName","description":"Replaces the LoadBalancer Service with the object in the body. Include metadata.resourceVersion from the last read."},"delete":{"summary":"Delete a LoadBalancer service","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"responses":{"200":{"description":"Kubernetes delete status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"deleteNetworkLoadBalancersByName","description":"Deletes the LoadBalancer Service and releases its External IP."}},"/network/{namespace}/endpoints":{"get":{"summary":"List service endpoints","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Kubernetes EndpointsList.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"getNetworkEndpoints","description":"The project's Endpoints as a Kubernetes list, to see which pods back each Service."}},"/network/{namespace}/pods":{"get":{"summary":"List pods for network targets","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Kubernetes PodList.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesResource"},"example":{"apiVersion":"v1","kind":"Resource","metadata":{},"spec":{},"status":{}}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"getNetworkPods","description":"The project's pods as a Kubernetes list, for choosing a Floating IP or Service target."}},"/network/{namespace}/vms/running":{"get":{"summary":"List running VMs with their interfaces","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Running VM instances.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"phase":{"type":"string","const":"Running"},"interfaces":{"type":"array","items":{"type":"object"}}}}}}},"example":{"items":[{"name":"web-1","namespace":"acme-web","phase":"Running","interfaces":[{}]}]}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"getNetworkVmsRunning","description":"Running VMs with their network interfaces, for choosing a Floating IP target."}},"/network/{namespace}/vms/{name}/interfaces":{"get":{"summary":"List a VM's network interfaces","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ResourceNameParam"}],"responses":{"200":{"description":"Interfaces reported by the running VM.","content":{"application/json":{"schema":{"type":"object","properties":{"interfaces":{"type":"array","items":{"$ref":"#/components/schemas/VmInterface"}}}},"example":{"interfaces":[{"name":"web-1","interfaceName":"web-1","mac":"mac","ipAddress":"10.0.10.15","ipAddresses":["ip-addresse"]}]}}}},"default":{"description":"Error passed through from Kubernetes."}},"operationId":"getNetworkVmsInterfaces","description":"A running VM's network interfaces with their MAC and IP addresses."}},"/network/{namespace}/routed-networks":{"get":{"summary":"List the project's routed network attachments","description":"Only available when Routed Networks are enabled on the platform.","tags":["Networking"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Attachments of this project.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/StatusEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RoutedNetworkAttachment"}}}}]},"example":{"status":"success","error":"Request failed.","data":[{"name":"web-1","namespace":"acme-web","allocation":"allocation","direction":"routed-egress","ready":true,"gateway":{"replicas":2,"readyReplicas":2,"haMode":"ha-mode"},"bgp":{},"destinations":["destination"],"advertised":["advertised"],"routes":{"accepted":1,"rejected":1}}]}}}},"403":{"description":"No access to the project."},"404":{"description":"Routed Networks are not enabled."}},"operationId":"getNetworkRoutedNetworks"}},"/manage-organization/routed-networks":{"get":{"summary":"List the organization's routed networks","description":"Routed network allocations assigned to the caller's organization, with their project attachments.","tags":["Networking"],"responses":{"200":{"description":"Allocations.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/StatusEnvelope"},{"type":"object","properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/RoutedNetworkAllocation"}}}}]},"example":{"status":"success","error":"Request failed.","data":[{"name":"web-1","phase":"Running","sharing":"multiple-projects","destinations":["destination"],"attachedProjects":["attached-project"],"attachments":[{"name":"web-1","namespace":"acme-web","allocation":"allocation","direction":"routed-egress","ready":true,"gateway":{"replicas":2,"readyReplicas":2,"haMode":"ha-mode"},"bgp":{},"destinations":["destination"],"advertised":["advertised"],"routes":{"accepted":1,"rejected":1},"project":"web"}],"ready":true,"message":"Done."}]}}}},"404":{"description":"Routed Networks are not enabled."}},"operationId":"getManageOrganizationRoutedNetworks"}},"/manage-organization/routed-networks/{allocation}/attach":{"post":{"summary":"Attach a project to a routed network","tags":["Networking"],"parameters":[{"name":"allocation","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the routed network allocation."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["project"],"properties":{"project":{"type":"string","description":"Project name (not namespace)."}}},"example":{"project":"web"}}}},"responses":{"201":{"description":"Attachment created.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/StatusEnvelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"}}}}}]},"example":{"status":"success","error":"Request failed.","data":{"name":"web-1","namespace":"acme-web"}}}}},"400":{"description":"Invalid project name."},"404":{"description":"Allocation is not assigned to the organization."},"409":{"description":"The project is already attached."}},"operationId":"postManageOrganizationRoutedNetworksAttach","description":"Connects a project to one of the organization's routed networks; the platform deploys a gateway that routes between them. Requires org-admin."}},"/manage-organization/routed-networks/{allocation}/attach/{project}":{"delete":{"summary":"Detach a project from a routed network","tags":["Networking"],"parameters":[{"name":"allocation","in":"path","required":true,"schema":{"type":"string"},"description":"Name of the routed network allocation."},{"$ref":"#/components/parameters/ProjectParam"}],"responses":{"200":{"description":"Detach started.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/StatusEnvelope"},{"type":"object","properties":{"data":{"type":"object","properties":{"state":{"type":"string","const":"terminating"}}}}}]},"example":{"status":"success","error":"Request failed.","data":{"state":"terminating"}}}}},"403":{"description":"The allocation belongs to another organization."},"404":{"description":"No such attachment."}},"operationId":"deleteManageOrganizationRoutedNetworksAttachByProject","description":"Disconnects the project from the routed network; its gateway is removed. Requires org-admin."}},"/kms/{namespace}":{"get":{"summary":"List KMS keys","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Keys in the project.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/KMSKeySummary"}}}},"example":{"items":[{"name":"web-1","namespace":"acme-web","creationTimestamp":"2026-10-01T09:30:00Z","purpose":"application","algorithm":"aes256-gcm96","deletionPolicy":"retain","rotation":{"enabled":true,"interval":"720h"},"exportable":true,"status":{"keyId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","currentVersion":1,"minDecryptionVersion":1,"lastRotatedTime":"2026-10-01T09:30:00Z","nextRotationTime":"2026-10-01T09:30:00Z","scheduledDeletion":"2026-10-01T09:30:00Z","conditions":[{}]}}]}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getKmsByNamespace","description":"The project's encryption keys with their version and rotation state."}},"/kms/{namespace}/{name}":{"get":{"summary":"Get a KMS key","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"responses":{"200":{"description":"Key metadata and status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KMSKeySummary"},"example":{"name":"app-data","namespace":"acme-web","creationTimestamp":"2026-10-03T00:58:16Z","purpose":"application","algorithm":"aes256-gcm96","deletionPolicy":"retain","rotation":{},"exportable":false,"status":{"keyId":"acme/transit/keys/acme-web-app-data","currentVersion":2,"minDecryptionVersion":1,"lastRotatedTime":"2026-10-03T00:58:21Z","conditions":[{"lastTransitionTime":"2026-10-03T00:58:16Z","message":"","reason":"Mounted","status":"True","type":"OpenBaoMounted"},{"lastTransitionTime":"2026-10-03T00:58:16Z","message":"spec.rotation.enabled=false","reason":"RotationDisabled","status":"False","type":"RotationScheduled"}]}}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getKmsByName","description":"One key's settings and state."},"post":{"summary":"Create a KMS key","description":"Creates a KMSKey. The controller provisions the OpenBao Transit key asynchronously; data-plane calls return 409 until `status.keyId` is set.","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KmsKeyCreate"},"example":{"purpose":"application","algorithm":"aes256-gcm96","deletionPolicy":"retain","rotation":{"enabled":true,"interval":"90d"}}}}},"responses":{"201":{"description":"Key created.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KMSKeySummary"},"example":{"name":"app-data","namespace":"acme-web","creationTimestamp":"2026-10-03T00:58:16Z","purpose":"application","algorithm":"aes256-gcm96","deletionPolicy":"retain","rotation":{"enabled":false},"exportable":false,"status":{"currentVersion":0,"minDecryptionVersion":0,"conditions":[]}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postKmsByName"},"delete":{"summary":"Delete a KMS key","description":"Deletes the KMSKey. The Transit key is cleaned up by the controller according to `deletionPolicy`.","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"responses":{"200":{"description":"Deletion accepted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"},"example":{"name":"app-data","namespace":"acme-web","deleted":true}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"deleteKmsByName"}},"/kms/{namespace}/{name}/yaml":{"get":{"summary":"Get KMS key YAML","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"responses":{"200":{"$ref":"#/components/responses/ResourceYaml"},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getKmsYaml","description":"The KMSKey manifest as YAML."},"put":{"summary":"Replace KMS key YAML","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"requestBody":{"required":true,"description":"Full resource manifest. Replaces the stored object.","content":{"application/yaml":{"schema":{"type":"string"},"example":"apiVersion: security.kube-dc.com/v1alpha1\nkind: KMSKey\nmetadata:\n  name: app-data\n  namespace: acme-web\n  resourceVersion: \"184866\"\nspec:\n  purpose: application\n  algorithm: aes256-gcm96\n  deletionPolicy: retain\n  rotation:\n    enabled: true\n    interval: 30d\n"}}},"responses":{"200":{"description":"Updated object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KMSKey"},"example":{"apiVersion":"security.kube-dc.com/v1alpha1","kind":"KMSKey","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"algorithm":"aes256-gcm96","deletionPolicy":"retain","exportable":false,"purpose":"application","rotation":{"enabled":true,"interval":"30d"}},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"currentVersion":1,"keyId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","lastRotatedTime":"2026-10-01T09:30:00Z","minDecryptionVersion":1,"nextRotationTime":"2026-10-01T09:30:00Z","scheduledDeletion":"2026-10-01T09:30:00Z"}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"putKmsYaml","description":"Replaces the KMSKey manifest, for example to change its rotation schedule."}},"/kms/{namespace}/{name}/rotate":{"post":{"summary":"Rotate a KMS key","description":"Adds a new key version. Requires project-manager or higher.","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"responses":{"200":{"description":"Key rotated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/KmsKeyAction"},{"type":"object","properties":{"rotated":{"type":"boolean","const":true}}}]},"example":{"name":"app-data","namespace":"acme-web","keyName":"acme-web-app-data","rotated":true,"reconcileTriggered":true}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}},"503":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"A required service is unavailable; retry later."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postKmsRotate"}},"/kms/{namespace}/{name}/encrypt":{"post":{"summary":"Encrypt data","description":"Encrypts up to 64 KiB with the key's current version. Use envelope encryption for larger payloads. Available to every project role.","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Pass `plaintext` (UTF-8) or `plaintextB64` (base64, for binary data).","properties":{"plaintext":{"type":"string"},"plaintextB64":{"type":"string","format":"byte"},"context":{"type":"string","description":"Optional derivation context; the same value is required to decrypt."}}},"example":{"plaintext":"card-holder:Jane Doe"}}}},"responses":{"200":{"description":"Ciphertext.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"keyName":{"type":"string"},"ciphertext":{"type":"string","example":"vault:v1:8SDd3WHDOjf7mq69CyCqYjBXAiQQAVZRkFM13ok481zoCmHnSeDX9vyf7w=="}}},"example":{"name":"app-data","namespace":"acme-web","ciphertext":"vault:v1:zc5tN92xarcwykzthjumHV5FcHZU69QE+YHpPg8VtDSW","keyName":"acme-web-app-data"}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}},"413":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The request is too large."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postKmsEncrypt"}},"/kms/{namespace}/{name}/decrypt":{"post":{"summary":"Decrypt data","description":"Requires project developer or higher.","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ciphertext"],"properties":{"ciphertext":{"type":"string","description":"OpenBao ciphertext, `vault:v<n>:...`."},"context":{"type":"string"}}},"example":{"ciphertext":"vault:v1:8SDd3WHDOjf7mq69CyCqYjBXAiQQAVZRkFM13ok481zoCmHnSeDX9vyf7w=="}}}},"responses":{"200":{"description":"Plaintext in both UTF-8 and base64 form.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"keyName":{"type":"string"},"plaintext":{"type":"string"},"plaintextB64":{"type":"string","format":"byte"}}},"example":{"name":"app-data","namespace":"acme-web","plaintext":"<redacted>","plaintextB64":"aGVsbG8=","keyName":"acme-web-app-data"}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postKmsDecrypt"}},"/kms/{namespace}/{name}/min-decryption-version":{"post":{"summary":"Set minimum decryption version","description":"Refuses decryption of ciphertext produced by older key versions. Requires project-manager or higher.","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["version"],"properties":{"version":{"type":"integer","minimum":1}}},"example":{"version":2}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/KmsKeyAction"},{"type":"object","properties":{"minDecryptionVersion":{"type":"integer"}}}]},"example":{"name":"app-data","namespace":"acme-web","keyName":"acme-web-app-data","minDecryptionVersion":1,"reconcileTriggered":true}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postKmsMinDecryptionVersion"}},"/kms/{namespace}/{name}/schedule-delete":{"post":{"summary":"Schedule key deletion","description":"Sets `deletionPolicy` to `schedule`, so the Transit key is destroyed after the grace period once the KMSKey is deleted.","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"responses":{"200":{"description":"Policy updated.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"deletionPolicy":{"type":"string","const":"schedule"}}},"example":{"name":"app-data","namespace":"acme-web","deletionPolicy":"schedule"}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postKmsScheduleDelete"}},"/kms/{namespace}/{name}/cancel-delete":{"post":{"summary":"Cancel scheduled key deletion","description":"Sets `deletionPolicy` back to `retain`.","tags":["KMS"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/KmsKeyName"}],"responses":{"200":{"description":"Policy updated.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"deletionPolicy":{"type":"string","const":"retain"}}},"example":{"name":"app-data","namespace":"acme-web","deletionPolicy":"retain"}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postKmsCancelDelete"}},"/k8s-clusters/{namespace}/endpoint-options":{"get":{"summary":"Get cluster endpoint options","description":"Which API endpoint modes and worker settings new clusters in this project can use.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Options.","content":{"application/json":{"schema":{"type":"object","properties":{"projectInternalEnabled":{"type":"boolean","description":"Whether a project-internal API endpoint is allowed."},"workerMTU":{"type":"integer","description":"Worker MTU override; 0 means default."},"mutationPreconditions":{"type":"boolean"},"publicAPISourcePolicyAvailable":{"type":"boolean","description":"Operator-qualified client CIDR enforcement for ProjectInternal public APIs in this namespace. Defaults to false; CRD support alone is insufficient."}}},"example":{"projectInternalEnabled":false,"workerMTU":0,"mutationPreconditions":true}}}}},"operationId":"getK8sClustersEndpointOptions"}},"/k8s-clusters/{namespace}/clusters/{name}/yaml":{"get":{"summary":"Get cluster YAML","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"}],"responses":{"200":{"description":"The KdcCluster spec and status as YAML.","content":{"text/yaml":{"schema":{"type":"string"}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getK8sClustersClustersYaml","description":"The cluster's spec and status as YAML, with trimmed metadata."}},"/k8s-clusters/{namespace}/clusters/{name}/worker-overview":{"get":{"summary":"Get worker node overview","description":"Worker nodes with readiness, size and last-hour CPU/memory usage.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"}],"responses":{"200":{"description":"Worker nodes.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string","description":"Node name."},"machine":{"type":"string"},"pool":{"type":"string"},"phase":{"type":"string","enum":["Ready","NotReady","Terminating","Unknown"]},"reason":{"type":"string"},"version":{"type":"string"},"provider":{"type":"string"},"vm":{"type":"string"},"cpuCores":{"type":["integer","null"]},"memoryBytes":{"type":["integer","null"]},"cpu":{"type":["number","null"],"description":"Usage percent."},"memory":{"type":["number","null"],"description":"Usage percent."}}}},"source":{"type":"string"},"observedAt":{"type":"string","format":"date-time"}}},"example":{"items":[{"name":"web-1","machine":"machine","pool":"general","phase":"Ready","reason":"Ready","version":"1","provider":"provider","vm":"vm","cpuCores":1,"memoryBytes":1,"cpu":1,"memory":1}],"source":"source","observedAt":"2026-10-01T09:30:00Z"}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getK8sClustersClustersWorkerOverview"}},"/k8s-clusters/{namespace}/clusters/{name}/worker-vms":{"get":{"summary":"List worker VMs","description":"KubeVirt VMs backing the cluster's workers, including ones still provisioning.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"}],"responses":{"200":{"description":"Worker VMs.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"uid":{"type":"string"},"pool":{"type":["string","null"]}}}},"pools":{"type":"array","items":{"type":"string"}}}},"example":{"items":[{"name":"web-1","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","pool":"general"}],"pools":["general"]}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getK8sClustersClustersWorkerVms"}},"/k8s-clusters/{namespace}/clusters/{name}/encryption":{"patch":{"summary":"Enable etcd encryption","description":"Turns on encryption at rest for the cluster's etcd. The request must carry the cluster's current UID and spec, so it fails with 409 if the cluster changed.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["uid","expectedSpec","payload"],"properties":{"uid":{"type":"string"},"expectedSpec":{"type":"object","description":"The cluster spec as last read."},"payload":{"type":"object","required":["enabled","confirmation"],"properties":{"enabled":{"type":"boolean","const":true},"confirmation":{"type":"string","description":"The cluster name","typed to confirm.":null}}}}},"example":{"uid":"7b8c9d0e-1f2a-4b3c-8d4e-5f6a7b8c9d0e","expectedSpec":{"version":"v1.33.4","encryption":{"etcd":{"enabled":false}}},"payload":{"enabled":true,"confirmation":"prod"}}}}},"responses":{"200":{"description":"Encryption requested.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"warning":{"type":"string"}}},"example":{"success":true,"warning":"warning"}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}}},"operationId":"patchK8sClustersClustersEncryption"}},"/k8s-clusters/{namespace}/clusters/{name}/worker-pools":{"post":{"summary":"Add a worker pool","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/WorkerPool"},{"required":["name"]}]},"example":{"name":"gpu","replicas":2,"cpuCores":8,"memory":"32Gi","diskSize":"100Gi"}}}},"responses":{"200":{"description":"Pool added.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ActionResult"},{"type":"object","properties":{"pool":{"$ref":"#/components/schemas/WorkerPool"}}}]},"example":{"success":true,"message":"Done.","pool":{"name":"web-1","replicas":2,"cpuCores":1,"memory":"4Gi","infrastructureProvider":"kubevirt","storageType":"storage-type","image":"nginx:1.27","diskSize":"40Gi"}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}}},"operationId":"postK8sClustersClustersWorkerPools","description":"Adds a worker pool to the cluster. Body: `name`, `replicas` (default 2), `cpuCores` (default 1), `memory` (default 2Gi), and optional `storageType`, `image`, `diskSize`."}},"/k8s-clusters/{namespace}/clusters/{name}/worker-pools/{pool}":{"patch":{"summary":"Update a worker pool","description":"Changing CPU, memory, image, storage or disk replaces the pool's VMs. Changing only `replicas` scales in place.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"},{"$ref":"#/components/parameters/WorkerPoolName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkerPool"},"example":{"replicas":4,"cpuCores":4,"memory":"8Gi"}}}},"responses":{"200":{"description":"Pool updated.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/ActionResult"},{"type":"object","properties":{"pool":{"$ref":"#/components/schemas/WorkerPool"}}}]},"example":{"success":true,"message":"Done.","pool":{"name":"web-1","replicas":2,"cpuCores":1,"memory":"4Gi","infrastructureProvider":"kubevirt","storageType":"storage-type","image":"nginx:1.27","diskSize":"40Gi"}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}}},"operationId":"patchK8sClustersClustersWorkerPoolsByPool"},"delete":{"summary":"Remove a worker pool","description":"The last pool cannot be removed.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"},{"$ref":"#/components/parameters/WorkerPoolName"}],"responses":{"200":{"description":"Pool removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ActionResult"},"example":{"success":true,"message":"Done."}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}}},"operationId":"deleteK8sClustersClustersWorkerPoolsByPool"}},"/k8s-clusters/{namespace}/clusters/{name}/snapshots":{"get":{"summary":"List etcd snapshots","description":"Snapshots stored in the project's backup bucket, `<namespace>-managed-k8s-backups`.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"}],"responses":{"200":{"description":"Snapshots.","content":{"application/json":{"schema":{"type":"object","properties":{"bucketName":{"type":"string"},"snapshots":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string","example":"prod/etcd-2026-10-01.db"},"size":{"type":"integer"},"lastModified":{"type":["string","null"],"format":"date-time"}}}}}},"example":{"bucketName":"assets","snapshots":[{"key":"prod/etcd-2026-10-01.db","size":1,"lastModified":"2026-10-01T09:30:00Z"}]}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getK8sClustersClustersSnapshots"}},"/k8s-clusters/{namespace}/clusters/{name}/snapshot":{"post":{"summary":"Take an etcd snapshot now","description":"Requests a snapshot outside the daily schedule. Poll the snapshot list for the returned job's result.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"}],"responses":{"200":{"description":"Snapshot requested.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"jobName":{"type":"string"}}},"example":{"success":true,"jobName":"web-1"}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}}},"operationId":"postK8sClustersClustersSnapshot"}},"/k8s-clusters/{namespace}/clusters/{name}/restore":{"post":{"summary":"Restore etcd from a snapshot","description":"Starts an asynchronous restore. Track it with the cluster's `RestoreReady` condition.","tags":["Managed Clusters"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/ClusterName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["snapshotKey"],"properties":{"snapshotKey":{"type":"string","example":"prod/etcd-2026-10-01.db"}}},"example":{"snapshotKey":"acme-web-managed-k8s-backups/prod/snapshot-20261002-020000.db"}}}},"responses":{"200":{"description":"Restore started.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"snapshotKey":{"type":"string"}}},"example":{"success":true,"snapshotKey":"snapshot-key"}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}}},"operationId":"postK8sClustersClustersRestore"}},"/database-credentials/{namespace}":{"get":{"summary":"List credential policies","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Policies in the project.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/DatabaseCredentialPolicySummary"}}}},"example":{"items":[{"name":"web-1","namespace":"acme-web","creationTimestamp":"2026-10-01T09:30:00Z","databaseRef":"database-ref","mode":"static-rotated","username":"jdoe","rotation":{},"sync":{},"role":"developer","ttl":"1h","maxTtl":"24h","status":{"endpoint":"https://web.acme-web.kube-dc.example","username":"jdoe","targetSecretName":"web-tls","lastRotatedTime":"2026-10-01T09:30:00Z","nextRotationTime":"2026-10-01T09:30:00Z","leaseSupported":true,"conditions":[{}]}}]}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getDatabaseCredentialsByNamespace","description":"The project's database credential policies."}},"/database-credentials/{namespace}/{name}":{"get":{"summary":"Get a credential policy","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CredentialPolicyName"}],"responses":{"200":{"description":"The policy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseCredentialPolicySummary"},"example":{"name":"web-1","namespace":"acme-web","creationTimestamp":"2026-10-01T09:30:00Z","databaseRef":"database-ref","mode":"static-rotated","username":"jdoe","rotation":{},"sync":{},"role":"developer","ttl":"1h","maxTtl":"24h","status":{"endpoint":"https://web.acme-web.kube-dc.example","username":"jdoe","targetSecretName":"web-tls","lastRotatedTime":"2026-10-01T09:30:00Z","nextRotationTime":"2026-10-01T09:30:00Z","leaseSupported":true,"conditions":[{}]}}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getDatabaseCredentialsByName","description":"One policy's settings and rotation state."},"post":{"summary":"Create a credential policy","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CredentialPolicyName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","spec"],"properties":{"name":{"type":"string","description":"Must match the path."},"spec":{"$ref":"#/components/schemas/DatabaseCredentialPolicySpec"}}},"example":{"name":"orders-app","spec":{"databaseRef":{"name":"orders"},"mode":"static-rotated","username":"app","rotation":{"interval":"30d"},"sync":{"enabled":true,"targetSecretName":"orders-app"}}}}}},"responses":{"201":{"description":"Created; returns the stored object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseCredentialPolicy"},"example":{"apiVersion":"security.kube-dc.com/v1alpha1","kind":"DatabaseCredentialPolicy","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"databaseRef":{"name":""},"maxTtl":"24h","mode":"static-rotated","role":"developer","rotation":{"interval":"30d","strategy":"rolling"},"sync":{"enabled":true,"targetSecretName":"web-tls"},"ttl":"1h","username":"app"},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"endpoint":"https://web.acme-web.kube-dc.example","lastRotatedTime":"2026-10-01T09:30:00Z","leaseSupported":true,"nextRotationTime":"2026-10-01T09:30:00Z","targetSecretName":"web-tls","username":"jdoe"}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postDatabaseCredentialsByName","description":"Creates a policy that gives a database user rotated (static) or per-request (dynamic) passwords, managed by OpenBao."},"delete":{"summary":"Delete a credential policy","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CredentialPolicyName"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"},"example":{"name":"web-1","namespace":"acme-web","deleted":true}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"deleteDatabaseCredentialsByName","description":"Deletes the policy. The database user is cleaned up by the platform."}},"/database-credentials/{namespace}/{name}/rotate":{"post":{"summary":"Rotate the database password","description":"Static-rotated policies only. Requires project-manager or higher. `root=true` is retired and returns 410.","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CredentialPolicyName"},{"name":"root","in":"query","description":"Retired. `root=true` (rotating the management user) answers 410.","schema":{"type":"string","enum":["true","false"]}}],"responses":{"200":{"description":"Password rotated.","content":{"application/json":{"schema":{"type":"object","properties":{"rotated":{"type":"boolean","const":true},"target":{"type":"string"},"reconcileTriggered":{"type":"boolean"}}},"example":{"rotated":true,"target":"target","reconcileTriggered":true}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"410":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Gone."}}}},"503":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"A required service is unavailable; retry later."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postDatabaseCredentialsRotate"}},"/database-credentials/{namespace}/{name}/credentials":{"get":{"summary":"Read current credentials","description":"Static-rotated policies only. Requires project-manager or higher; the read is audited.","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CredentialPolicyName"}],"responses":{"200":{"description":"Credentials.","content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"},"lastVaultRotation":{"type":"string","format":"date-time"},"rotationPeriod":{"type":"integer","description":"Seconds."},"ttl":{"type":"integer","description":"Seconds until the next rotation."}}},"example":{"username":"jdoe","password":"<password>","lastVaultRotation":"2026-10-01T09:30:00Z","rotationPeriod":1,"ttl":1}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getDatabaseCredentialsCredentials"}},"/database-credentials/{namespace}/{name}/issue":{"post":{"summary":"Issue dynamic credentials","description":"Dynamic policies only. Returns a short-lived user; 501 while dynamic mode is not available on the cluster.","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CredentialPolicyName"}],"responses":{"200":{"description":"New credentials and their lease.","content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string"},"leaseId":{"type":"string"},"leaseDuration":{"type":"integer","description":"Seconds."}}},"example":{"username":"jdoe","password":"<password>","leaseId":"database/creds/app/k3XyZ9","leaseDuration":1}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"501":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not available on this installation."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postDatabaseCredentialsIssue"}},"/database-credentials/{namespace}/{name}/yaml":{"get":{"summary":"Get credential policy YAML","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CredentialPolicyName"}],"responses":{"200":{"$ref":"#/components/responses/ResourceYaml"},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getDatabaseCredentialsYaml","description":"The DatabaseCredentialPolicy manifest as YAML."},"put":{"summary":"Replace credential policy YAML","tags":["Database Credentials"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CredentialPolicyName"}],"requestBody":{"required":true,"description":"Full resource manifest. Replaces the stored object.","content":{"application/yaml":{"schema":{"type":"string"},"example":"apiVersion: security.kube-dc.com/v1alpha1\nkind: DatabaseCredentialPolicy\nmetadata:\n  name: orders-app\n  namespace: acme-web\n  resourceVersion: \"184790\"\nspec:\n  databaseRef:\n    name: orders\n  mode: static-rotated\n  username: app\n  rotation:\n    interval: 7d\n"}}},"responses":{"200":{"description":"Updated object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DatabaseCredentialPolicy"},"example":{"apiVersion":"security.kube-dc.com/v1alpha1","kind":"DatabaseCredentialPolicy","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"databaseRef":{"name":""},"maxTtl":"24h","mode":"static-rotated","role":"developer","rotation":{"interval":"30d","strategy":"rolling"},"sync":{"enabled":true,"targetSecretName":"web-tls"},"ttl":"1h","username":"app"},"status":{"conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"endpoint":"https://web.acme-web.kube-dc.example","lastRotatedTime":"2026-10-01T09:30:00Z","leaseSupported":true,"nextRotationTime":"2026-10-01T09:30:00Z","targetSecretName":"web-tls","username":"jdoe"}}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"putDatabaseCredentialsYaml","description":"Replaces the DatabaseCredentialPolicy manifest."}},"/certificates/{namespace}":{"get":{"summary":"List certificates","tags":["Certificates"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Certificates in the project.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/ManagedCertificateSummary"}}}},"example":{"items":[{"name":"web-1","namespace":"acme-web","creationTimestamp":"2026-10-01T09:30:00Z","type":"private","purpose":"server","dnsNames":["web-1"],"duration":"2160h","renewBefore":"360h","targetSecretName":"web-tls","status":{"issuer":"issuer","certificateSecretName":"web-tls","notBefore":"2026-10-01T09:30:00Z","notAfter":"2026-10-01T09:30:00Z","renewalTime":"2026-10-01T09:30:00Z","conditions":[{}]}}]}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getCertificatesByNamespace","description":"The project's managed certificates with their validity and renewal times."}},"/certificates/{namespace}/{name}":{"get":{"summary":"Get a certificate","tags":["Certificates"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CertificateName"}],"responses":{"200":{"description":"Certificate metadata and status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedCertificateSummary"},"example":{"name":"api","namespace":"acme-web","creationTimestamp":"2026-10-03T00:58:21Z","type":"private","purpose":"server","dnsNames":["api.web.internal"],"duration":"90d","renewBefore":"15d","targetSecretName":"api-tls","status":{"conditions":[]}}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getCertificatesByName","description":"One certificate's settings and state."},"post":{"summary":"Request a certificate","tags":["Certificates"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CertificateName"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["dnsNames"],"properties":{"type":{"type":"string","enum":["private","public"],"default":"private"},"purpose":{"type":"string","enum":["server","client","mtls","code-signing"],"default":"server"},"dnsNames":{"type":"array","minItems":1,"items":{"type":"string"},"description":"Names must fall within the project's allowed zones. By default a private certificate may name `<project>.internal` and its subdomains; public zones are set per project by the organization.","example":["api.web.internal"]},"targetSecretName":{"type":"string","description":"Secret that receives the key pair. Defaults to `<name>-tls`."},"duration":{"type":"string","example":"2160h"},"renewBefore":{"type":"string","example":"360h"}}},"example":{"type":"private","purpose":"server","dnsNames":["api.web.internal"],"targetSecretName":"api-tls","duration":"2160h","renewBefore":"360h"}}}},"responses":{"201":{"description":"Certificate requested.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedCertificateSummary"},"example":{"name":"api","namespace":"acme-web","creationTimestamp":"2026-10-03T00:58:21Z","type":"private","purpose":"server","dnsNames":["api.web.internal"],"duration":"90d","renewBefore":"15d","targetSecretName":"api-tls","status":{"conditions":[]}}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"403":{"description":"Not allowed, including a DNS name outside the project's allowed zones (the admission message names it).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/KubernetesStatus"},"example":{"kind":"Status","apiVersion":"v1","status":"Failure","message":"Not allowed, including a DNS name outside the project's allowed zones (the admission message names it).","reason":"Forbidden","code":403}}}},"409":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"The resource changed since it was read; read it again and retry."}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postCertificatesByName","description":"Requests a certificate for the given DNS names. It is issued asynchronously and written to a Kubernetes Secret, then renewed automatically."},"delete":{"summary":"Delete a certificate","description":"The issued Secret is removed with it.","tags":["Certificates"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CertificateName"}],"responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeleteResult"},"example":{"name":"api","namespace":"acme-web","deleted":true}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"deleteCertificatesByName"}},"/certificates/{namespace}/{name}/renew":{"post":{"summary":"Renew a certificate now","tags":["Certificates"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CertificateName"}],"responses":{"200":{"description":"Re-issue requested.","content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"renewRequestedAt":{"type":"string","format":"date-time"}}},"example":{"name":"api","namespace":"acme-web","renewRequestedAt":"2026-10-03T00:58:21.990Z"}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postCertificatesRenew","description":"Issues a new certificate now instead of waiting for the renewal time."}},"/certificates/{namespace}/{name}/yaml":{"get":{"summary":"Get certificate YAML","tags":["Certificates"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CertificateName"}],"responses":{"200":{"$ref":"#/components/responses/ResourceYaml"},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getCertificatesYaml","description":"The ManagedCertificate manifest as YAML."},"put":{"summary":"Replace certificate YAML","tags":["Certificates"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"},{"$ref":"#/components/parameters/CertificateName"}],"requestBody":{"required":true,"description":"Full resource manifest. Replaces the stored object.","content":{"application/yaml":{"schema":{"type":"string"},"example":"apiVersion: security.kube-dc.com/v1alpha1\nkind: ManagedCertificate\nmetadata:\n  name: api\n  namespace: acme-web\n  resourceVersion: \"184880\"\nspec:\n  type: private\n  purpose: server\n  dnsNames:\n  - api.web.internal\n  - www.web.internal\n  targetSecretName: api-tls\n"}}},"responses":{"200":{"description":"Updated object.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ManagedCertificate"},"example":{"apiVersion":"security.kube-dc.com/v1alpha1","kind":"ManagedCertificate","metadata":{"name":"web-1","namespace":"acme-web","uid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","resourceVersion":"184702","generation":1,"creationTimestamp":"2026-10-01T09:30:00Z","deletionTimestamp":"2026-10-01T09:30:00Z","labels":{"app":"labels"},"annotations":{"app":"annotations"},"finalizers":["finalizer"]},"spec":{"dnsNames":["web-1"],"duration":"90d","ipAddresses":["ip-addresse"],"purpose":"server","renewBefore":"15d","targetSecretName":"web-tls","type":"private"},"status":{"certificateSecretName":"web-tls","conditions":[{"lastTransitionTime":"2026-10-01T09:30:00Z","message":"Done.","observedGeneration":1,"reason":"Ready","status":"True","type":"Ready"}],"issuer":"issuer","notAfter":"2026-10-01T09:30:00Z","notBefore":"2026-10-01T09:30:00Z","renewalTime":"2026-10-01T09:30:00Z"}}}}},"default":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"putCertificatesYaml","description":"Replaces the ManagedCertificate manifest, for example to change its DNS names or duration."}},"/billing/config":{"get":{"summary":"Get billing configuration","description":"Which payment provider serves the caller's organization and which billing features the console should offer.","tags":["Billing"],"responses":{"200":{"description":"Configuration.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"provider":{"type":"string","example":"stripe"},"features":{"type":"object","additionalProperties":{"type":"boolean"}}}}}}]},"example":{"success":true,"data":{"provider":"whmcs","features":{"quotas":true,"plans":true,"checkout":false,"portal":false,"webhooks":true,"addons":true,"metering":false}},"timestamp":"2026-10-03T00:57:51.499Z","message":"Billing configuration"}}}}},"operationId":"getBillingConfig"}},"/billing/plans":{"get":{"summary":"List subscription plans","description":"Plans the organization can buy.","tags":["Billing"],"security":[],"responses":{"200":{"description":"Plans.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}}}}]},"example":{"success":true,"data":[{"id":"dev-pool","name":"dev-pool","displayName":"Dev Pool","description":"Best for: Sandbox / Dev","price":19,"currency":"EUR","priceUnit":"month","recommended":false,"burstRatio":1,"resources":{"cpu":4,"memory":8,"storage":60,"gpu":{},"objectStorage":20,"ipv4":1,"pods":100},"selfService":true,"features":["4 vCPU","8 GB RAM"]},{"id":"pro-pool","name":"pro-pool","displayName":"Pro Pool","description":"Best for: Production / Teams","price":49,"currency":"EUR","priceUnit":"month","recommended":true,"burstRatio":1,"resources":{"cpu":8,"memory":24,"storage":160,"gpu":{},"objectStorage":100,"ipv4":1,"pods":200},"selfService":true,"features":["8 vCPU","24 GB RAM"]}],"timestamp":"2026-10-03T00:57:51.551Z","message":"Plans retrieved successfully"}}}},"500":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingPlans"}},"/billing/addons":{"get":{"summary":"List add-ons","description":"Turbo add-ons that extend a plan's quota.","tags":["Billing"],"security":[],"responses":{"200":{"description":"Add-ons.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"array","items":{"type":"object"}}}}]},"example":{"success":true,"data":[{"id":"turbo-x1","name":"turbo-x1","displayName":"Turbo x1","description":"+4 GB RAM • +2 vCPU","price":9,"currency":"EUR","priceUnit":"month","resources":{"cpu":2,"memory":4,"gpu":{},"storage":20,"ipv4":0}},{"id":"turbo-x2","name":"turbo-x2","displayName":"Turbo x2","description":"+8 GB RAM • +4 vCPU","price":16,"currency":"EUR","priceUnit":"month","resources":{"cpu":4,"memory":8,"gpu":{},"storage":40,"ipv4":0}}],"timestamp":"2026-10-03T00:57:51.597Z","message":"Add-ons retrieved successfully"}}}},"500":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingAddons"}},"/billing/organization-subscription":{"get":{"summary":"Get the organization's subscription","description":"Current plan, add-ons and trial state, plus `governance`, which says whether a pay-as-you-go billing policy applies instead.","tags":["Billing"],"responses":{"200":{"description":"Subscription.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object"}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingOrganizationSubscription"},"post":{"summary":"Subscribe to a plan","description":"With Stripe, returns a Checkout session to redirect to; call `verify-checkout` after the redirect. Without a payment provider, sets the plan directly. Requires org-admin.","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["planId"],"properties":{"planId":{"type":"string"},"promoCode":{"type":"string","description":"Stripe only."}}},"example":{"planId":"dev-pool"}}}},"responses":{"200":{"description":"Checkout session (Stripe) or the new subscription.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"anyOf":[{"allOf":[{"$ref":"#/components/schemas/CheckoutSession"},{"type":"object","properties":{"withTrial":{"type":"boolean"},"trialDays":{"type":"integer"}}}]},{"$ref":"#/components/schemas/SubscriptionChange"}]}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"checkoutUrl":"https://web.acme-web.kube-dc.example","sessionId":"cs_test_a1B2c3D4e5F6g7H8i9J0","withTrial":true,"trialDays":1}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingOrganizationSubscription"},"put":{"summary":"Change plan","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["planId"],"properties":{"planId":{"type":"string"}}},"example":{"planId":"pro-pool"}}}},"responses":{"200":{"description":"Plan changed.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/SubscriptionChange"}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"organization":"acme","planId":"dev-pool","planName":"Dev Pool","status":"active"}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"putBillingOrganizationSubscription","description":"Moves the organization to another plan. With Stripe, the change is prorated on the next invoice. Requires org-admin."},"delete":{"summary":"Cancel the subscription","description":"With Stripe, cancels at the end of the billing period (`status` is `canceling`). Without a payment provider, cancels immediately.","tags":["Billing"],"responses":{"200":{"description":"Cancellation accepted.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"organization":{"type":"string"},"status":{"type":"string","enum":["canceling","none"]},"message":{"type":"string"}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"organization":"acme","status":"canceling","message":"Done."}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"deleteBillingOrganizationSubscription"}},"/billing/verify-checkout":{"post":{"summary":"Complete a Stripe checkout","description":"Call after Stripe redirects back, to activate the subscription. Safe to repeat.","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"string"}}},"example":{"sessionId":"cs_test_a1B2c3D4e5F6g7H8i9J0"}}}},"responses":{"200":{"description":"Subscription active.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"allOf":[{"$ref":"#/components/schemas/SubscriptionChange"},{"type":"object","properties":{"isTrial":{"type":"boolean"},"trialEndDate":{"type":"string","format":"date-time"},"providerSubscriptionId":{"type":"string"}}}]}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"organization":"acme","planId":"dev-pool","planName":"Dev Pool","status":"active","isTrial":true,"trialEndDate":"2026-10-01T09:30:00Z","providerSubscriptionId":"3f2504e0-4f89-41d3-9a0c-0305e82c3301"}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingVerifyCheckout"}},"/billing/organization-subscription/addons":{"post":{"summary":"Add an add-on","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["addonId"],"properties":{"addonId":{"type":"string"},"quantity":{"type":"integer","minimum":1,"default":1}}},"example":{"addonId":"turbo","quantity":1}}}},"responses":{"200":{"description":"Add-on added.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"organization":{"type":"string"},"addon":{"type":"string"},"quantity":{"type":"integer"}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"organization":"acme","addon":"addon","quantity":2}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingOrganizationSubscriptionAddons","description":"Adds a turbo add-on (extra quota) to the subscription, or more of one. Requires org-admin."}},"/billing/organization-subscription/addons/{addonId}":{"delete":{"summary":"Remove an add-on","description":"Reduces the add-on's quantity by one.","tags":["Billing"],"parameters":[{"name":"addonId","in":"path","required":true,"schema":{"type":"string"},"description":"Id of the add-on, as listed by the add-ons endpoint."}],"responses":{"200":{"description":"Add-on removed or reduced.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"organization":{"type":"string"},"removedAddon":{"type":"string"},"remainingQuantity":{"type":"integer"}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"organization":"acme","removedAddon":"removed-addon","remainingQuantity":2}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"deleteBillingOrganizationSubscriptionAddonsByAddonId"}},"/billing/customer-portal":{"post":{"summary":"Open the Stripe customer portal","description":"Returns a one-time link where the user manages payment methods and invoices.","tags":["Billing"],"responses":{"200":{"description":"Portal session.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"portalUrl":{"type":"string","format":"uri"}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"portalUrl":"https://web.acme-web.kube-dc.example"}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingCustomerPortal"}},"/billing/simulate-downgrade":{"post":{"summary":"Check a plan downgrade","description":"Whether the organization's current usage fits within another plan.","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["targetPlanId"],"properties":{"targetPlanId":{"type":"string"}}},"example":{"targetPlanId":"dev-pool"}}}},"responses":{"200":{"description":"Result.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"safe":{"type":"boolean"},"exceeds":{"type":"array","items":{"type":"object"},"description":"Resources whose usage is above the target plan's limits."},"targetPlan":{"type":"object","properties":{"id":{"type":"string"},"displayName":{"type":"string"}}}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"safe":true,"exceeds":[{}],"targetPlan":{"id":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","displayName":"Acme Web"}}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingSimulateDowngrade"}},"/billing/trial-eligibility":{"get":{"summary":"Check trial eligibility","tags":["Billing"],"responses":{"200":{"description":"Eligibility.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"isEligible":{"type":"boolean"},"trialDays":{"type":"integer"},"organization":{"type":"string"}}}}}]},"example":{"success":true,"data":{"isEligible":false,"trialDays":14,"organization":"acme"},"timestamp":"2026-10-03T00:57:52.555Z","message":"Trial has already been used"}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingTrialEligibility","description":"Whether the organization can still start a free trial, and how long it lasts."}},"/billing/validate-promo":{"post":{"summary":"Validate a promo code","description":"Usable without signing in, during registration.","tags":["Billing"],"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"example":{"code":"WELCOME30"}}}},"responses":{"200":{"description":"The promo code's terms.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object"}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingValidatePromo"}},"/billing/activate-promo-trial":{"post":{"summary":"Activate a promo trial","description":"Starts a trial from a promo code without payment. Requires org-admin and no active subscription.","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["code"],"properties":{"code":{"type":"string"}}},"example":{"code":"WELCOME30"}}}},"responses":{"200":{"description":"Trial active.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object"}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingActivatePromoTrial"}},"/billing/quota-usage":{"get":{"summary":"Get organization quota usage","description":"Live usage against the organization's plan quota.","tags":["Billing"],"responses":{"200":{"description":"Usage.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"enforced":{"type":"boolean"},"usage":{"type":["object","null"]}}}}}]},"example":{"success":true,"data":{"enforced":true,"usage":{"cpu":{"used":0,"limit":4},"memory":{"used":0,"limit":8},"storage":{"used":0,"limit":60},"pods":{"used":0,"limit":100}}},"timestamp":"2026-10-03T00:57:52.585Z","message":"Quota usage retrieved"}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingQuotaUsage"}},"/billing/quota-status":{"get":{"summary":"Get quota enforcement status","tags":["Billing"],"responses":{"200":{"description":"Status.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"exists":{"type":"boolean"},"enforced":{"type":"boolean"},"status":{"type":"string"},"planId":{"type":["string","null"]},"resourceCount":{"type":"integer"}}}}}]},"example":{"success":true,"data":{"exists":true,"enforced":true,"status":"Active","planId":"dev-pool","resourceCount":7},"timestamp":"2026-10-03T00:57:52.609Z","message":"Quota status retrieved"}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingQuotaStatus","description":"Whether the plan's quota is in place and enforced for the organization."}},"/billing/organization-resources":{"get":{"summary":"Get allocated and used resources","description":"The organization's allocated versus used CPU, memory, storage and other resources.","tags":["Billing"],"responses":{"200":{"description":"Resources.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object"}}}]},"example":{"success":true,"data":{"organization":"acme","quotaSource":"plan","planId":"dev-pool","suspended":false,"suspendedBy":null,"enforced":true,"lastUpdated":"2026-10-03T00:57:35Z","dimensions":[{"key":"cpu","label":"CPU","unit":"cores","allocated":4,"used":0},{"key":"memory","label":"Memory","unit":"GiB","allocated":8,"used":0}],"gpu":[]},"timestamp":"2026-10-03T00:57:52.748Z","message":"Organization resources retrieved"}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingOrganizationResources"}},"/billing/project-usage/{namespace}":{"get":{"summary":"Get project resource counts","tags":["Billing"],"parameters":[{"$ref":"#/components/parameters/ProjectNamespace"}],"responses":{"200":{"description":"Counts of the project's resources.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"namespace":{"type":"string"},"pods":{"type":"object","properties":{"total":{"type":"integer"},"running":{"type":"integer"}}},"vms":{"type":"object","properties":{"total":{"type":"integer"},"running":{"type":"integer"}}},"storage":{"type":"object","properties":{"volumes":{"type":"integer"},"totalGi":{"type":"number"}}},"loadBalancers":{"type":"integer"},"publicIPs":{"type":"integer"}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"namespace":"acme-web","pods":{"total":2,"running":1},"vms":{"total":2,"running":1},"storage":{"volumes":1,"totalGi":1},"loadBalancers":1,"publicIPs":1}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingProjectUsageByNamespace","description":"Counts of the project's pods, VMs, volumes, load balancers and public IPs."}},"/billing/accelerator-entitlement-status":{"get":{"summary":"Get GPU entitlement status","description":"Whether the GPU quota from the organization's subscription has been applied.","tags":["Billing"],"responses":{"200":{"description":"Status.","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"},"data":{"type":"object","properties":{"phase":{"type":"string","enum":["ready","reconciling"]},"ready":{"type":"boolean"},"desired":{"type":"object"},"observed":{"type":"object"},"subscription":{"type":"object"}}}}},"example":{"success":true,"data":{"phase":"ready","ready":true,"desired":{},"observed":{},"subscription":{}}}}}},"404":{"description":"The organization has no subscription."},"503":{"description":"GPU quota status is temporarily unavailable."}},"operationId":"getBillingAcceleratorEntitlementStatus"}},"/billing/account-restrictions":{"get":{"summary":"Get account restrictions","description":"Whether a financial hold stops the organization from creating new resources. Always 200; `known` is false when the state cannot be read right now. Pay-as-you-go installations only.","tags":["Billing"],"responses":{"200":{"description":"Restriction state.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"known":{"type":"boolean"},"restricted":{"type":["boolean","null"]},"state":{"type":["string","null"]},"reason":{"type":"string","description":"Customer-facing reason","when restricted.":null}}}}}]},"example":{"success":true,"data":{"known":true,"restricted":false,"state":"active"},"timestamp":"2026-10-03T00:57:53.018Z","message":"Account restrictions"}}}}},"operationId":"getBillingAccountRestrictions"}},"/billing/payg/terms":{"get":{"summary":"Get pay-as-you-go terms","description":"Whether pay-as-you-go is offered and on what terms, before the user commits.","tags":["Billing"],"responses":{"200":{"description":"Terms.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"available":{"type":"boolean"},"reason":{"type":"string"},"requiresCard":{"type":"boolean"},"limits":{"type":"object"}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"available":true,"reason":"Ready","requiresCard":true,"limits":{}}}}}},"401":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Missing or invalid bearer token.","status":401,"message":"Missing or invalid bearer token."}}}},"500":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingPaygTerms"}},"/billing/payg/card-session":{"post":{"summary":"Start card validation for pay-as-you-go","description":"Returns a Stripe Checkout session in setup mode. Nothing is charged.","tags":["Billing"],"responses":{"200":{"description":"Session.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CheckoutSession"}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"checkoutUrl":"https://web.acme-web.kube-dc.example","sessionId":"cs_test_a1B2c3D4e5F6g7H8i9J0"}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingPaygCardSession"}},"/billing/payg/activate":{"post":{"summary":"Switch to pay-as-you-go","description":"Verifies the card from the setup session, then moves the organization to pay-as-you-go. Returns once the new quota ceiling is enforced.","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["sessionId"],"properties":{"sessionId":{"type":"string"}}},"example":{"sessionId":"cs_test_a1B2c3D4e5F6g7H8i9J0"}}}},"responses":{"200":{"description":"Pay-as-you-go active.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"organization":{"type":"string"},"terms":{"type":"object"},"trialEndsAt":{"type":"string","format":"date-time"}}}}}]},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"organization":"acme","terms":{},"trialEndsAt":"2026-10-01T09:30:00Z"}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"postBillingPaygActivate"}},"/billing/payg/usage":{"get":{"summary":"Get pay-as-you-go usage estimate","description":"Usage priced at the current rate card. Always 200; `available` is false with a `reason` when there is nothing to estimate or the data cannot be read.","tags":["Billing"],"parameters":[{"name":"days","in":"query","description":"Look-back window. Cannot be combined with `period`.","schema":{"type":"integer","minimum":1,"default":30}},{"name":"period","in":"query","schema":{"type":"string","enum":["current_month"]},"description":"`current_month` for the month to date, instead of `days`."}],"responses":{"200":{"description":"Estimate.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/OrgSuccess"},{"type":"object","properties":{"data":{"type":"object","properties":{"available":{"type":"boolean"},"reason":{"type":"string","enum":["not_payg","policy_unavailable","metering_unavailable","rate_card_unavailable"]}}}}}]},"example":{"success":true,"data":{"available":false,"reason":"not_payg"},"timestamp":"2026-10-03T00:57:53.073Z","message":"Usage estimate"}}}},"400":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request: name must be a valid Kubernetes name.","status":400,"message":"Invalid request: name must be a valid Kubernetes name."}}}}},"operationId":"getBillingPaygUsage"}},"/billing/budget":{"get":{"summary":"Get the monthly budget","description":"The organization's advisory budget and month-to-date spend. A budget only alerts; it never limits anything.","tags":["Billing"],"responses":{"200":{"description":"Budget status.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"contractVersion":"payg.kube-dc.com/v1alpha1","organization":"acme","organizationUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","period":"2026-10-01T09:30:00Z","asOf":"2026-10-01T09:30:00Z","budget":{"contractVersion":"payg.kube-dc.com/v1alpha1","amount":"1","currency":"EUR","thresholds":[1],"version":1,"updatedAt":"2026-10-01T09:30:00Z","updatedBy":"jdoe"},"spend":"1","spendBasis":"total","usageSource":"metering.resource_usage_events+metering.usage_events","currency":"EUR","usedPercent":"1","remaining":"1","alerts":[{"period":"2026-10-01T09:30:00Z","threshold":1,"spend":"1","currency":"EUR","lowerBound":true,"budgetAmount":"1","budgetVersion":1,"raisedAt":"2026-10-01T09:30:00Z","notifiedAt":"2026-10-01T09:30:00Z"}],"note":""}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingBudget"},"put":{"summary":"Set the monthly budget","description":"Creates (`version` 0) or replaces the budget. Requires update access to the organization.","tags":["Billing"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetInput"},"example":{"amount":"500.00","currency":"EUR","thresholds":[50,80,100],"version":0}}}},"responses":{"200":{"description":"Saved budget.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/BudgetResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"contractVersion":"payg.kube-dc.com/v1alpha1","organization":"acme","organizationUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","period":"2026-10-01T09:30:00Z","asOf":"2026-10-01T09:30:00Z","budget":{"contractVersion":"payg.kube-dc.com/v1alpha1","amount":"1","currency":"EUR","thresholds":[1],"version":1,"updatedAt":"2026-10-01T09:30:00Z","updatedBy":"jdoe"},"spend":"1","spendBasis":"total","usageSource":"metering.resource_usage_events+metering.usage_events","currency":"EUR","usedPercent":"1","remaining":"1","alerts":[{"period":"2026-10-01T09:30:00Z","threshold":1,"spend":"1","currency":"EUR","lowerBound":true,"budgetAmount":"1","budgetVersion":1,"raisedAt":"2026-10-01T09:30:00Z","notifiedAt":"2026-10-01T09:30:00Z"}],"note":""}}}}},"400":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request: name must be a valid Kubernetes name.","status":400,"message":"Invalid request: name must be a valid Kubernetes name."}}}},"409":{"description":"The budget changed since it was read."}},"operationId":"putBillingBudget"},"delete":{"summary":"Remove the monthly budget","tags":["Billing"],"parameters":[{"name":"version","in":"query","required":true,"description":"The version read.","schema":{"type":"integer","minimum":1}}],"responses":{"200":{"description":"Removed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgSuccess"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done."}}}},"400":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Invalid request: name must be a valid Kubernetes name.","status":400,"message":"Invalid request: name must be a valid Kubernetes name."}}}},"409":{"description":"The budget changed since it was read."}},"operationId":"deleteBillingBudget","description":"Removes the monthly budget. Query: `version` as last read."}},"/billing/forecast":{"get":{"summary":"Get the month-end spend forecast","tags":["Billing"],"responses":{"200":{"description":"Forecast.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ForecastResponse"},"example":{"success":true,"timestamp":"2026-10-01T09:30:00Z","message":"Done.","data":{"contractVersion":"payg.kube-dc.com/v1alpha1","organization":"acme","organizationUid":"3f2504e0-4f89-41d3-9a0c-0305e82c3301","period":"2026-10-01T09:30:00Z","asOf":"2026-10-01T09:30:00Z","available":true,"method":"run-rate-v1","basis":"total","usageSource":"metering.resource_usage_events+metering.usage_events","lowerBound":true,"monthToDate":"1","projected":"1","currency":"EUR","confidence":"low","assumptions":["assumption"],"reasons":["Ready"],"coverage":[{"sku":"compute.cpu","meter":"cpu_core_seconds","source":"source","state":"complete","expectedIntervals":1,"observedIntervals":1,"watermark":"2026-10-01T09:30:00Z","gaps":[{"contractVersion":"payg.kube-dc.com/v1alpha1","producerId":"cell.zrh.postgresql","epoch":"epoch","fromSequence":"from-sequence","toSequence":"to-sequence","windowStart":"2026-10-01T09:30:00Z","windowEnd":"2026-10-01T09:30:00Z","meters":["cpu_core_seconds"],"reason":"Ready","detectedAt":"2026-10-01T09:30:00Z","repairedAt":"2026-10-01T09:30:00Z"}],"moreGaps":true,"qualification":"draft","pricingStatus":"priced","note":""}]}}}}},"default":{"description":"Error.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrgError"},"example":{"success":false,"error":"Internal error.","status":500,"message":"Internal error."}}}}},"operationId":"getBillingForecast","description":"The estimated spend at the end of the month, with the method and confidence of the estimate."}},"/audit/orgs/{org}":{"get":{"summary":"Query the organization audit log","description":"Security events (secret, certificate, KMS and database-credential access) across the organization. Requires org-admin.","tags":["Audit"],"parameters":[{"$ref":"#/components/parameters/OrganizationParam"},{"$ref":"#/components/parameters/AuditService"},{"$ref":"#/components/parameters/AuditActor"},{"$ref":"#/components/parameters/AuditResult"},{"$ref":"#/components/parameters/AuditSince"},{"$ref":"#/components/parameters/AuditUntil"},{"$ref":"#/components/parameters/AuditLimit"}],"responses":{"200":{"description":"Matching events, newest first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditEvents"},"example":{"events":[{"ts":"2026-10-03T00:57:51.474Z","labels":{"action":"certificates.list","detected_level":"unknown","org":"acme","project":"web","result":"allowed","service":"certificates","service_name":"certificates"},"body":{"org":"acme","project":"web","service":"certificates","action":"certificates.list","result":"allowed","actor":"admin","actor_groups":["org-admin"],"actor_sub":"3f2504e0-4f89-41d3-9a0c-000000000004","actor_email":"jane@acme.example","resource":null,"request_id":"3f2504e0-4f89-41d3-9a0c-000000000005","source_ip":"203.0.113.10","elevation_id":null,"extra":{"namespace":"acme-web","count":0},"ts":"2026-10-03T00:57:51.474Z"}},{"ts":"2026-10-03T00:57:51.413Z","labels":{"action":"database-credentials.list","detected_level":"unknown","org":"acme","project":"web","result":"allowed","service":"database-credentials","service_name":"database-credentials"},"body":{"org":"acme","project":"web","service":"database-credentials","action":"database-credentials.list","result":"allowed","actor":"admin","actor_groups":["org-admin"],"actor_sub":"3f2504e0-4f89-41d3-9a0c-000000000004","actor_email":"jane@acme.example","resource":null,"request_id":"3f2504e0-4f89-41d3-9a0c-000000000006","source_ip":"203.0.113.10","elevation_id":null,"extra":{"namespace":"acme-web","count":0},"ts":"2026-10-03T00:57:51.413Z"}}],"query":"{org=\"acme\"}","returned":133,"limit":500}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"403":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getAuditOrgsByOrg"}},"/audit/orgs/{org}/projects/{project}":{"get":{"summary":"Query a project audit log","description":"Available to members of the project.","tags":["Audit"],"parameters":[{"$ref":"#/components/parameters/OrganizationParam"},{"$ref":"#/components/parameters/ProjectParam"},{"$ref":"#/components/parameters/AuditService"},{"$ref":"#/components/parameters/AuditActor"},{"$ref":"#/components/parameters/AuditResult"},{"$ref":"#/components/parameters/AuditSince"},{"$ref":"#/components/parameters/AuditUntil"},{"$ref":"#/components/parameters/AuditLimit"}],"responses":{"200":{"description":"Matching events, newest first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuditEvents"},"example":{"events":[{"ts":"2026-10-03T00:57:51.474Z","labels":{"action":"certificates.list","detected_level":"unknown","org":"acme","project":"web","result":"allowed","service":"certificates","service_name":"certificates"},"body":{"org":"acme","project":"web","service":"certificates","action":"certificates.list","result":"allowed","actor":"admin","actor_groups":["org-admin"],"actor_sub":"3f2504e0-4f89-41d3-9a0c-000000000004","actor_email":"jane@acme.example","resource":null,"request_id":"3f2504e0-4f89-41d3-9a0c-000000000005","source_ip":"203.0.113.10","elevation_id":null,"extra":{"namespace":"acme-web","count":0},"ts":"2026-10-03T00:57:51.474Z"}},{"ts":"2026-10-03T00:57:51.413Z","labels":{"action":"database-credentials.list","detected_level":"unknown","org":"acme","project":"web","result":"allowed","service":"database-credentials","service_name":"database-credentials"},"body":{"org":"acme","project":"web","service":"database-credentials","action":"database-credentials.list","result":"allowed","actor":"admin","actor_groups":["org-admin"],"actor_sub":"3f2504e0-4f89-41d3-9a0c-000000000004","actor_email":"jane@acme.example","resource":null,"request_id":"3f2504e0-4f89-41d3-9a0c-000000000006","source_ip":"203.0.113.10","elevation_id":null,"extra":{"namespace":"acme-web","count":0},"ts":"2026-10-03T00:57:51.413Z"}}],"query":"{org=\"acme\",project=\"web\"}","returned":3,"limit":500}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"403":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getAuditOrgsProjectsByProject"}},"/audit/orgs/{org}/csv":{"get":{"summary":"Export the organization audit log as CSV","description":"Same filters as the JSON query; without `limit` it exports up to 5000 events. Requires org-admin.","tags":["Audit"],"parameters":[{"$ref":"#/components/parameters/OrganizationParam"},{"$ref":"#/components/parameters/AuditService"},{"$ref":"#/components/parameters/AuditActor"},{"$ref":"#/components/parameters/AuditResult"},{"$ref":"#/components/parameters/AuditSince"},{"$ref":"#/components/parameters/AuditUntil"},{"$ref":"#/components/parameters/AuditLimit"}],"responses":{"200":{"description":"CSV file download.","content":{"text/csv":{"schema":{"type":"string"}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"403":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getAuditOrgsCsv"}},"/orgs/{org}/projects/{project}/elevate":{"get":{"summary":"Get elevation state","description":"Whether the calling org-admin currently has elevated access to the project.","tags":["Organization"],"parameters":[{"$ref":"#/components/parameters/OrganizationParam"},{"$ref":"#/components/parameters/ProjectParam"}],"responses":{"200":{"description":"Elevation state.","content":{"application/json":{"schema":{"allOf":[{"type":"object","properties":{"active":{"type":"boolean"}}},{"$ref":"#/components/schemas/Elevation"}]},"example":{"active":true,"elevationId":"elv-M5b78XWEnoS","user":"admin","org":"acme","project":"web","reason":"api contract check","grantedAt":"2026-10-03T00:58:29.433Z","expiresAt":"2026-10-03T01:13:29.433Z","ttlSeconds":900}}}},"403":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getOrgsProjectsElevate"},"post":{"summary":"Elevate to a project","description":"Grants the calling org-admin 15 minutes of access to the project's secret values. The grant and every read under it are audited.","tags":["Organization"],"parameters":[{"$ref":"#/components/parameters/OrganizationParam"},{"$ref":"#/components/parameters/ProjectParam"}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reason"],"properties":{"reason":{"type":"string","description":"Why access is needed; recorded in the audit log."}}},"example":{"reason":"Investigating failed checkout deployment (INC-4521)."}}}},"responses":{"200":{"description":"Elevation granted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Elevation"},"example":{"elevationId":"elv-M5b78XWEnoS","user":"admin","org":"acme","project":"web","reason":"api contract check","grantedAt":"2026-10-03T00:58:29.433Z","expiresAt":"2026-10-03T01:13:29.433Z","ttlSeconds":900}}}},"400":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Invalid request: name must be a valid Kubernetes name."}}}},"403":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"postOrgsProjectsElevate"},"delete":{"summary":"End elevation early","tags":["Organization"],"parameters":[{"$ref":"#/components/parameters/OrganizationParam"},{"$ref":"#/components/parameters/ProjectParam"}],"responses":{"200":{"description":"Elevation ended.","content":{"application/json":{"schema":{"allOf":[{"$ref":"#/components/schemas/Elevation"},{"type":"object","properties":{"releasedAt":{"type":"string","format":"date-time"}}}]},"example":{"elevationId":"elv-M5b78XWEnoS","user":"admin","org":"acme","project":"web","reason":"api contract check","grantedAt":"2026-10-03T00:58:29.433Z","expiresAt":"2026-10-03T01:13:29.433Z","ttlSeconds":900,"releasedAt":"2026-10-03T00:58:29.450Z"}}}},"403":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}},"404":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Not found."}}}}},"operationId":"deleteOrgsProjectsElevate","description":"Ends the caller's elevation before it expires. Their access to the project's secret values stops immediately."}},"/orgs/{org}/elevations":{"get":{"summary":"List active elevations","description":"Active elevation grants in the organization. Requires org-admin.","tags":["Organization"],"parameters":[{"$ref":"#/components/parameters/OrganizationParam"}],"responses":{"200":{"description":"Active grants.","content":{"application/json":{"schema":{"type":"object","properties":{"items":{"type":"array","items":{"$ref":"#/components/schemas/Elevation"}}}},"example":{"items":[{"elevationId":"elv-M5b78XWEnoS","user":"admin","org":"acme","project":"web","reason":"api contract check","grantedAt":"2026-10-03T00:58:29.433Z","expiresAt":"2026-10-03T01:13:29.433Z","ttlSeconds":900}]}}}},"403":{"description":"Error. Kubernetes authorization failures are passed through with their status code.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiError"},"example":{"error":"Your role does not allow this."}}}}},"operationId":"getOrgsElevations"}}},"x-tagGroups":[{"name":"Compute","tags":["Virtual Machines","VM Configuration","Volumes","Accelerators"]},{"name":"Kubernetes","tags":["Workloads","Services & Ingress","ConfigMaps & Kubernetes Secrets","Managed Clusters","Cloud Shell"]},{"name":"Networking & Storage","tags":["Networking","Object Storage"]},{"name":"Databases & Services","tags":["Databases","Database Credentials","Managed Services: Catalog","Managed Services: Instances","Managed Services: Operations","Managed Services: Bindings","Managed Services: Credential policies","Managed Services: Backups","Managed Services: Replication groups","Managed Services: Data planes"]},{"name":"Security","tags":["Secrets","Certificates","KMS","Audit"]},{"name":"Organization","tags":["Organization","Registration"]},{"name":"Billing","tags":["Billing","Billing: Quotes","Billing: Reports","Billing: Budgets","Billing: Producers"]},{"name":"Platform","tags":["Platform"]}]}