{"openapi":"3.0.0","info":{"title":"Edge Portal BFF","version":"0.1.0","description":"BFF over kcp via APISIX.\n\n**Machine-readable OpenAPI spec:** [`/doc`](/doc) — fetch this URL for client codegen."},"components":{"schemas":{"AuthUser":{"type":"object","properties":{"id":{"type":"string"},"email":{"type":"string"},"user":{"type":"string"},"name":{"type":"string"},"givenName":{"type":"string"},"familyName":{"type":"string"},"preferredUsername":{"type":"string"},"homeOrg":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"primaryDomain":{"type":"string"}},"required":["id","name","primaryDomain"]},"groups":{"type":"array","items":{"type":"string"}},"platformRoles":{"type":"array","items":{"type":"string"}}},"required":["id","email","user","name","givenName","familyName","preferredUsername","homeOrg","groups","platformRoles"]},"Error":{"type":"object","properties":{"error":{"type":"string"}},"required":["error"]},"Workspace":{"type":"object","properties":{"name":{"type":"string"},"displayName":{"type":"string"},"description":{"type":"string"},"owners":{"type":"array","items":{"type":"string"}},"phase":{"type":"string","enum":["provisioning","ready","deleting","error"]},"ready":{"type":"boolean"},"createdAt":{"type":"string"}},"required":["name","displayName","owners","phase","ready"]},"WorkspaceInput":{"type":"object","properties":{"name":{"type":"string","minLength":1,"maxLength":63},"displayName":{"type":"string","minLength":1},"description":{"type":"string"}},"required":["name","displayName"]},"WorkspacePatch":{"type":"object","properties":{"displayName":{"type":"string","minLength":1},"description":{"type":"string"}}},"WorkspaceDeleting":{"type":"object","properties":{"name":{"type":"string"},"phase":{"type":"string","enum":["deleting"]}},"required":["name","phase"]},"ResourceEntry":{"type":"object","properties":{"apiVersion":{"type":"string"},"kind":{"type":"string"},"metadata":{"$ref":"#/components/schemas/ObjectMeta"},"spec":{"type":"object","additionalProperties":{"nullable":true}},"status":{"type":"object","additionalProperties":{"nullable":true}},"type":{"nullable":true},"data":{"nullable":true},"stringData":{"nullable":true},"binaryData":{"nullable":true},"rules":{"nullable":true},"aggregationRule":{"nullable":true},"subjects":{"nullable":true},"roleRef":{"nullable":true}},"required":["apiVersion","kind","metadata"]},"ObjectMeta":{"type":"object","properties":{"name":{"type":"string"},"namespace":{"type":"string"},"uid":{"type":"string"},"labels":{"type":"object","additionalProperties":{"type":"string"}},"annotations":{"type":"object","additionalProperties":{"type":"string"}},"creationTimestamp":{"type":"string"}},"required":["name"]},"ResourceKindInfo":{"type":"object","properties":{"group":{"type":"string"},"version":{"type":"string"},"kind":{"type":"string"},"plural":{"type":"string"},"namespaced":{"type":"boolean"}},"required":["group","version","kind","plural","namespaced"]},"ResourceCreated":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"},"status":{"type":"string"},"spec":{"type":"object","additionalProperties":{"nullable":true}},"createdAt":{"type":"string"},"type":{"nullable":true},"data":{"nullable":true},"stringData":{"nullable":true},"binaryData":{"nullable":true},"rules":{"nullable":true},"aggregationRule":{"nullable":true},"subjects":{"nullable":true},"roleRef":{"nullable":true}},"required":["id","kind","name","status","createdAt"]},"ResourceCreateInput":{"type":"object","properties":{"kind":{"type":"string"},"name":{"type":"string","minLength":2},"namespace":{"type":"string","minLength":1},"labels":{"type":"object","additionalProperties":{"type":"string"}},"annotations":{"type":"object","additionalProperties":{"type":"string"}},"spec":{"type":"object","additionalProperties":{"nullable":true}},"type":{"nullable":true},"data":{"nullable":true},"stringData":{"nullable":true},"binaryData":{"nullable":true},"rules":{"nullable":true},"aggregationRule":{"nullable":true},"subjects":{"nullable":true},"roleRef":{"nullable":true}},"required":["kind","name"]},"ResourceDeleted":{"type":"object","properties":{"deleted":{"type":"boolean","enum":[true]},"name":{"type":"string"},"kind":{"type":"string"},"namespace":{"type":"string"}},"required":["deleted","name","kind"]},"ResourcePatched":{"type":"object","properties":{"id":{"type":"string"},"kind":{"type":"string"},"name":{"type":"string"},"namespace":{"type":"string"},"status":{"type":"string"},"spec":{"type":"object","additionalProperties":{"nullable":true}},"type":{"nullable":true},"data":{"nullable":true},"stringData":{"nullable":true},"binaryData":{"nullable":true},"rules":{"nullable":true},"aggregationRule":{"nullable":true},"subjects":{"nullable":true},"roleRef":{"nullable":true}},"required":["id","kind","name","status"]},"ResourcePatchInput":{"type":"object","properties":{"kind":{"type":"string"},"namespace":{"type":"string","minLength":1},"spec":{"type":"object","additionalProperties":{"nullable":true}},"type":{"nullable":true},"data":{"nullable":true},"stringData":{"nullable":true},"binaryData":{"nullable":true},"rules":{"nullable":true},"aggregationRule":{"nullable":true},"subjects":{"nullable":true},"roleRef":{"nullable":true}},"required":["kind"]},"SsoConfig":{"type":"object","properties":{"configured":{"type":"boolean"},"displayName":{"type":"string"},"provider":{"type":"string","enum":["oidc","saml"]},"issuerUrl":{"type":"string"},"clientId":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"claimMappings":{"type":"object","properties":{"user":{"type":"string"},"groups":{"type":"string"}},"required":["user","groups"]},"clientSecretSet":{"type":"boolean"},"verified":{"type":"boolean"},"phase":{"type":"string","enum":["Active","Inactive","Error"]},"zitadelIdpId":{"type":"string"},"lastVerifiedAt":{"type":"string"},"observedClaims":{"type":"object","properties":{"paths":{"type":"array","items":{"type":"string"}},"truncated":{"type":"boolean"},"idpId":{"type":"string"},"observedAt":{"type":"string"}},"required":["paths"]}},"required":["configured","displayName","provider","issuerUrl","clientId","scopes","claimMappings","clientSecretSet","verified"]},"SsoConfigInput":{"type":"object","properties":{"displayName":{"type":"string"},"provider":{"type":"string","enum":["oidc","saml"]},"issuerUrl":{"type":"string"},"clientId":{"type":"string"},"scopes":{"type":"array","items":{"type":"string"}},"claimMappings":{"type":"object","properties":{"user":{"type":"string"},"groups":{"type":"string"}}},"clientSecret":{"type":"string"}}},"Registration":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"displayName":{"type":"string"},"phase":{"type":"string","enum":["pendingValidation","provisioning","ready","error","rejected"]},"validation":{"$ref":"#/components/schemas/ValidationState"},"conditions":{"type":"object","properties":{"identity":{"type":"boolean"},"workspace":{"type":"boolean"},"route":{"type":"boolean"}},"required":["identity","workspace","route"]},"ready":{"type":"boolean"},"portalUrl":{"type":"string"},"rejectionReason":{"type":"string"}},"required":["name","slug","displayName","phase","validation","conditions","ready"]},"ValidationState":{"type":"string","enum":["PendingValidation","Validated","Rejected"]},"RegistrationInput":{"type":"object","properties":{"slug":{"type":"string","minLength":1,"maxLength":63},"displayName":{"type":"string","minLength":1,"maxLength":200},"ownerEmail":{"type":"string","format":"email"},"givenName":{"type":"string","minLength":1},"familyName":{"type":"string","minLength":1},"organization":{"$ref":"#/components/schemas/OrganizationDetails"}},"required":["slug","displayName","ownerEmail","givenName","familyName"]},"OrganizationDetails":{"type":"object","properties":{"registrationNumber":{"type":"string","maxLength":100},"vatId":{"type":"string","maxLength":32},"domains":{"type":"array","items":{"type":"string","minLength":1,"maxLength":253},"maxItems":20},"contactName":{"type":"string","maxLength":200},"contactEmail":{"type":"string","format":"email"}}},"SlugAvailability":{"type":"object","properties":{"available":{"type":"boolean"},"reason":{"type":"string","enum":["reserved","taken"]}},"required":["available"]},"Organization":{"type":"object","properties":{"slug":{"type":"string"},"displayName":{"type":"string"},"organization":{"$ref":"#/components/schemas/OrganizationDetails"},"validation":{"$ref":"#/components/schemas/ValidationState"},"rejectionReason":{"type":"string"},"decidedAt":{"type":"string"},"createdAt":{"type":"string"}},"required":["slug","displayName","organization","validation"]},"OrganizationVerificationState":{"type":"object","properties":{"verified":{"type":"boolean"},"verifiedAt":{"type":"string"},"current":{"$ref":"#/components/schemas/OrganizationVerification"}},"required":["verified"]},"OrganizationVerification":{"type":"object","properties":{"id":{"type":"string"},"method":{"$ref":"#/components/schemas/VerificationMethod"},"status":{"$ref":"#/components/schemas/VerificationStatus"},"domain":{"type":"string"},"vatId":{"type":"string"},"roleMailbox":{"type":"string"},"challenge":{"$ref":"#/components/schemas/VerificationChallenge"},"createdAt":{"type":"string"},"expiresAt":{"type":"string"},"lastCheckedAt":{"type":"string"},"failureReason":{"type":"string"}},"required":["id","method","status","createdAt"]},"VerificationMethod":{"type":"string","enum":["dns-txt","well-known-file","role-email","vat-id"]},"VerificationStatus":{"type":"string","enum":["pending","checking","verified","failed","expired"]},"VerificationChallenge":{"type":"object","properties":{"recordName":{"type":"string"},"recordType":{"type":"string"},"recordValue":{"type":"string"},"fileUrl":{"type":"string"},"fileContent":{"type":"string"},"emailAddress":{"type":"string"}}},"StartVerificationRequest":{"oneOf":[{"type":"object","properties":{"method":{"type":"string","enum":["dns-txt"]},"domain":{"type":"string","minLength":1}},"required":["method","domain"]},{"type":"object","properties":{"method":{"type":"string","enum":["well-known-file"]},"domain":{"type":"string","minLength":1}},"required":["method","domain"]},{"type":"object","properties":{"method":{"type":"string","enum":["vat-id"]},"vatId":{"type":"string","minLength":1}},"required":["method","vatId"]},{"type":"object","properties":{"method":{"type":"string","enum":["role-email"]},"domain":{"type":"string","minLength":1},"roleMailbox":{"type":"string","enum":["admin","administrator","hostmaster","postmaster","webmaster"]}},"required":["method","domain","roleMailbox"]}]},"VerifyCodeRequest":{"type":"object","properties":{"code":{"type":"string","minLength":1}},"required":["code"]},"TenantRegistration":{"type":"object","properties":{"name":{"type":"string"},"slug":{"type":"string"},"displayName":{"type":"string"},"owner":{"type":"string"},"createdAt":{"type":"string"},"organization":{"$ref":"#/components/schemas/OrganizationDetails"},"phase":{"type":"string"},"decision":{"type":"object","properties":{"decision":{"type":"string"},"reviewedBy":{"type":"string"},"reviewedAt":{"type":"string"},"reason":{"type":"string"},"reference":{"type":"string"}},"required":["decision","reviewedBy"]},"tenantRef":{"type":"string"},"verification":{"$ref":"#/components/schemas/VerificationEvidence"},"verifications":{"type":"array","items":{"$ref":"#/components/schemas/VerificationEvidence"}},"provisioning":{"type":"string"}},"required":["name","slug","displayName","owner","phase","verifications"]},"VerificationEvidence":{"type":"object","properties":{"id":{"type":"string"},"method":{"type":"string"},"status":{"type":"string"},"domain":{"type":"string"},"vatId":{"type":"string"},"roleMailbox":{"type":"string"},"failureReason":{"type":"string"},"createdAt":{"type":"string"},"lastCheckedAt":{"type":"string"}},"required":["id","method","status"]},"RegistrationReviewInput":{"type":"object","properties":{"reason":{"type":"string","maxLength":1000},"reference":{"type":"string","maxLength":200}}},"Member":{"type":"object","properties":{"name":{"type":"string"},"username":{"type":"string"},"email":{"type":"string"},"givenName":{"type":"string"},"familyName":{"type":"string"},"displayName":{"type":"string"},"userPhase":{"type":"string","enum":["active","pending","error"]},"invite":{"$ref":"#/components/schemas/MemberInvite"},"createdAt":{"type":"string"}},"required":["name","username","email","givenName","familyName","userPhase","invite"]},"MemberInvite":{"type":"object","nullable":true,"properties":{"phase":{"type":"string","enum":["pending","sent","accepted","error"]},"sentAt":{"type":"string"}},"required":["phase"]},"MemberInput":{"type":"object","properties":{"email":{"type":"string","format":"email"},"givenName":{"type":"string","minLength":1},"familyName":{"type":"string","minLength":1},"displayName":{"type":"string","minLength":1}},"required":["email","givenName","familyName"]},"MemberRemoving":{"type":"object","properties":{"name":{"type":"string"},"status":{"type":"string","enum":["removing"]}},"required":["name","status"]}},"parameters":{}},"paths":{"/bff/me":{"get":{"summary":"Authenticated user","description":"Returns the user parsed from APISIX's X-Userinfo header.","responses":{"200":{"description":"The authenticated user","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AuthUser"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/workspaces":{"get":{"summary":"List workspaces","description":"The org's workspaces. A fresh org has none — the org itself is not a workspace.","responses":{"200":{"description":"Workspaces","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Workspace"}}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a workspace","description":"Create a workspace owned by the caller. Provisioning is asynchronous — poll the workspace or subscribe to its watch stream until it reports ready. The name is immutable.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceInput"}}}},"responses":{"201":{"description":"Workspace accepted, provisioning","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Name already taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid name","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/workspaces/{name}":{"get":{"summary":"Workspace status","parameters":[{"schema":{"type":"string","example":"production-eu"},"required":true,"name":"name","in":"path"}],"responses":{"200":{"description":"The workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update a workspace","description":"Update the mutable fields (displayName, description). The name is immutable.","parameters":[{"schema":{"type":"string","example":"production-eu"},"required":true,"name":"name","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspacePatch"}}}},"responses":{"200":{"description":"The updated workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Workspace"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"delete":{"summary":"Delete a workspace","description":"Asynchronous teardown (202). Refused with 409 while the workspace still contains resources.","parameters":[{"schema":{"type":"string","example":"production-eu"},"required":true,"name":"name","in":"path"}],"responses":{"202":{"description":"Teardown accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WorkspaceDeleting"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown workspace","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Workspace still contains resources","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/resources":{"get":{"summary":"List resources","description":"Platform resources in the workspace as generic KRM entries (kinds via kcp discovery). Set the X-Workspace header to target a workspace; otherwise the org workspace is used.","responses":{"200":{"description":"Resource instances","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResourceEntry"}}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Create a resource","description":"Create a platform resource with an opaque payload (stored verbatim): `spec` for the platform's own kinds, top-level fields (data, rules, subjects, …) for the core and RBAC kinds. The kind must be in the workspace catalog; if the spec declares a provider/region they're checked against the workspace constraints. Namespaced kinds take an optional namespace, which must already exist.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreateInput"}}}},"responses":{"200":{"description":"The created resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceCreated"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Resource violates workspace constraints","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/resources/schemas":{"get":{"summary":"Available resource kinds","description":"The resource kinds available in the workspace, discovered from kcp (group/version/kind/plural/namespaced). The catalog clients use to know what they can create.","responses":{"200":{"description":"Discovered resource kinds","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/ResourceKindInfo"}}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/resources/{name}":{"delete":{"summary":"Delete a resource","description":"Delete a platform resource by kind (query) + name (path). Namespaced kinds take an optional namespace (query); it defaults to `default`.","parameters":[{"schema":{"type":"string","example":"prod-cluster"},"required":true,"name":"name","in":"path"},{"schema":{"type":"string","example":"KubernetesCluster"},"required":false,"name":"kind","in":"query"},{"schema":{"type":"string","example":"default"},"required":false,"name":"namespace","in":"query"}],"responses":{"200":{"description":"Deletion result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourceDeleted"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"patch":{"summary":"Update a resource","description":"Shallow-merge a partial payload into the stored resource. Switching a provider is just merging `{ providerRef: { name } }`; rotating a Secret is merging `{ stringData }`. Set `namespace` to target a namespaced resource outside `default`.","parameters":[{"schema":{"type":"string","example":"prod-cluster"},"required":true,"name":"name","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourcePatchInput"}}}},"responses":{"200":{"description":"The updated resource","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ResourcePatched"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/sso":{"get":{"summary":"SSO configuration","description":"The org's SSOConfig, or a defaulted unconfigured shape when none exists.","responses":{"200":{"description":"SSO configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SsoConfig"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update SSO configuration","description":"Create or update the org's SSOConfig. For OIDC with a client secret, provisions a Secret in the sso namespace and references it. OIDC requires an issuer URL and a client ID.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/SsoConfigInput"}}}},"responses":{"200":{"description":"Updated SSO configuration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SsoConfig"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/registrations":{"post":{"summary":"Register an organization","description":"Create the organization's Tenant in root:orgs, unvalidated. It is provisioned at once and its owner invited, so they can sign in and submit verification evidence; a super-admin then validates (granting workspace admin) or rejects it. Poll /bff/registrations/{name} with the returned `name`, or subscribe to its watch stream.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationInput"}}}},"responses":{"201":{"description":"Organization created, pending validation","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Registration"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Slug already taken","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid or reserved slug","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/registrations/{name}":{"get":{"summary":"Registration status","description":"The organization's provisioning progress and the super-admin's validation verdict.","parameters":[{"schema":{"type":"string","example":"5f1c0a2e-7b3d-4e9a-9c21-0a1b2c3d4e5f"},"required":true,"name":"name","in":"path"}],"responses":{"200":{"description":"Registration status","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Registration"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown registration","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/registrations/{slug}/available":{"get":{"summary":"Slug availability","description":"Whether a slug is free for a new tenant — a live pre-check for the signup form. Advisory: the create call re-validates the slug and is authoritative.","parameters":[{"schema":{"type":"string","example":"acme-corp"},"required":true,"name":"slug","in":"path"}],"responses":{"200":{"description":"Slug availability","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SlugAvailability"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Malformed slug","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/organization":{"get":{"summary":"The caller's organization","description":"The submitted company details and the Platform Super Admin's validation verdict. An org that is not yet Validated can sign in and use these endpoints, but cannot administer its workspace.","responses":{"200":{"description":"Organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No organization for this host","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"put":{"summary":"Update the caller's organization details","description":"Replace the submitted company details (registration number, VAT ID, domains, contact). Editable in any validation state; every change is recorded in the audit log.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationDetails"}}}},"responses":{"200":{"description":"Updated organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Organization"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Caller is not the organization's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No organization for this host","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Concurrent update, retry","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid details","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/organization/verification":{"get":{"summary":"Current verification state of the caller's organization","responses":{"200":{"description":"Verification state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationVerificationState"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/organization/verifications":{"post":{"summary":"Start a verification; returns the minted challenge","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/StartVerificationRequest"}}}},"responses":{"201":{"description":"Verification started","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationVerification"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Caller is not the organization's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid domain, VAT id or mailbox","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Too many verification attempts","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/organization/verifications/{id}/check":{"post":{"summary":"Run the server-side check now","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"200":{"description":"Check requested","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationVerification"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Caller is not the organization's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Verification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/organization/verifications/{id}/code":{"post":{"summary":"Confirm the role-mailbox one-time code","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/VerifyCodeRequest"}}}},"responses":{"200":{"description":"Code accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OrganizationVerification"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Caller is not the organization's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Verification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid or expired code","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/organization/verifications/{id}":{"delete":{"summary":"Cancel a verification","parameters":[{"schema":{"type":"string"},"required":true,"name":"id","in":"path"}],"responses":{"204":{"description":"Cancelled"},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Caller is not the organization's owner","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Verification not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already decided; outcome records are kept","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/admin/registrations":{"get":{"summary":"List organizations for review","description":"Every organization (pending and decided) with its submitted details and all verification evidence.","responses":{"200":{"description":"Registrations","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/TenantRegistration"}}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/admin/registrations/{name}/approve":{"post":{"summary":"Validate an organization","description":"Record the super-admin's validation; the controller then grants the owner workspace admin. Allowed for a pending or a previously rejected organization.","parameters":[{"schema":{"type":"string","example":"acme-corp"},"required":true,"name":"name","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationReviewInput"}}}},"responses":{"200":{"description":"Approved","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantRegistration"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already validated, or a concurrent decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/admin/registrations/{name}/reject":{"post":{"summary":"Reject an organization","description":"Record a rejection with a reason. Only a pending organization can be rejected; it stays (its user can sign in and see the verdict) and may be validated later.","parameters":[{"schema":{"type":"string","example":"acme-corp"},"required":true,"name":"name","in":"path"}],"requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationReviewInput"}}}},"responses":{"200":{"description":"Rejected","content":{"application/json":{"schema":{"$ref":"#/components/schemas/TenantRegistration"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown organization","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Already decided, or a concurrent decision","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"A reason is required to reject","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/users":{"get":{"summary":"List members","description":"The org's members, each with its Zitadel invitation state.","responses":{"200":{"description":"Members","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Member"}}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"summary":"Invite a member","description":"Seed a passwordless member and email them a Zitadel invitation to set their own credential. Provisioning is asynchronous — the invite is sent once the user exists in Zitadel.","requestBody":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberInput"}}}},"responses":{"201":{"description":"Member accepted, invite pending","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A member with this email already exists","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"422":{"description":"Invalid input","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/users/{name}/resend":{"post":{"summary":"Resend a member's invite","description":"Issue a fresh invite code and invalidate the previous one.","parameters":[{"schema":{"type":"string","example":"alice-example-com"},"required":true,"name":"name","in":"path"}],"responses":{"200":{"description":"Invite resent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Member"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown member or invite","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/users/{name}":{"delete":{"summary":"Remove a member","description":"Delete the member and their invite. Zitadel deprovisioning is asynchronous.","parameters":[{"schema":{"type":"string","example":"alice-example-com"},"required":true,"name":"name","in":"path"}],"responses":{"202":{"description":"Removal accepted","content":{"application/json":{"schema":{"$ref":"#/components/schemas/MemberRemoving"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Unknown member","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/kubeconfig":{"get":{"summary":"Download organization kubeconfig","parameters":[{"schema":{"type":"string","enum":["true","false"],"description":"Skip Kubernetes API and OIDC issuer certificate verification for local environments with self-signed certificates. Defaults to false.","example":"true"},"required":false,"description":"Skip Kubernetes API and OIDC issuer certificate verification for local environments with self-signed certificates. Defaults to false.","name":"skipTls","in":"query"}],"responses":{"200":{"description":"Credential-free kubeconfig YAML","content":{"application/yaml":{"schema":{"type":"string"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Profile access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Workspace is hidden or absent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Unexpected upstream failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Profile or workspace is not ready","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/bff/workspaces/{workspace}/kubeconfig":{"get":{"summary":"Download workspace kubeconfig","parameters":[{"schema":{"type":"string"},"required":true,"name":"workspace","in":"path"},{"schema":{"type":"string","enum":["true","false"],"description":"Skip Kubernetes API and OIDC issuer certificate verification for local environments with self-signed certificates. Defaults to false.","example":"true"},"required":false,"description":"Skip Kubernetes API and OIDC issuer certificate verification for local environments with self-signed certificates. Defaults to false.","name":"skipTls","in":"query"}],"responses":{"200":{"description":"Credential-free kubeconfig YAML","content":{"application/yaml":{"schema":{"type":"string"}}}},"400":{"description":"Bad request (e.g. host has no derivable org slug)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Not authenticated (missing X-Userinfo or session cookie)","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Profile access denied","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Workspace is hidden or absent","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"502":{"description":"Unexpected upstream failure","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Profile or workspace is not ready","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}}}