openapi: 3.1.0
info:
  title: GlobalStacks Public API
  version: 0.1.0
  description: >
    V1 public HTTP contract for the GlobalStacks control plane. This document is
    the contract-first source of truth for operator and UI clients.
  license:
    name: Proprietary
    url: https://globalstacks.dev/terms
servers:
  - url: https://api.globalstacks.dev
security:
  - cookieAuth: []
tags:
  - name: Auth
    description: Session creation, inspection, and logout.
  - name: Tenants
    description: Tenant-scoped management entrypoints.
  - name: Organizations
    description: Company workspaces, team members, and invitations.
  - name: Sandboxes
    description: Secure sandbox execution surfaces.
  - name: Clusters
    description: Infrastructure clusters that provide sandbox capacity.
  - name: Integrations
    description: Provider integrations, marketplace catalog, and tenant installs.
  - name: Data Plane
    description: Durable tenant data-plane services and object-store resources.
paths:
  /v1/auth/session:
    get:
      tags: [Auth]
      summary: Get the current authenticated session.
      operationId: getSession
      responses:
        "200":
          description: Current session information.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      tags: [Auth]
      summary: Create a session using a supported login method.
      operationId: createSession
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateSessionRequest"
      responses:
        "200":
          description: Session created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SessionResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
    delete:
      tags: [Auth]
      summary: End the current session.
      operationId: deleteSession
      responses:
        "204":
          description: Session terminated.
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/tenants:
    get:
      tags: [Tenants]
      summary: List tenants visible to the caller.
      operationId: listTenants
      responses:
        "200":
          description: Tenant list.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TenantListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      tags: [Tenants]
      summary: Create a tenant.
      operationId: createTenant
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateTenantRequest"
      responses:
        "201":
          description: Tenant created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Tenant"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/organizations:
    get:
      tags: [Organizations]
      summary: List organizations visible to the caller.
      operationId: listOrganizations
      responses:
        "200":
          description: Organization list.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      tags: [Organizations]
      summary: Create an organization.
      operationId: createOrganization
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateOrganizationRequest"
      responses:
        "201":
          description: Organization created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Organization"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/organizations/{organizationId}/activate:
    post:
      tags: [Organizations]
      summary: Set the active organization for the current session.
      operationId: activateOrganization
      parameters:
        - $ref: "#/components/parameters/OrganizationId"
      responses:
        "200":
          description: Active organization changed.
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/organizations/current:
    get:
      tags: [Organizations]
      summary: Get the active organization, members, and pending invitations.
      operationId: getCurrentOrganization
      responses:
        "200":
          description: Active organization.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/CurrentOrganizationResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    patch:
      tags: [Organizations]
      summary: Rename the active organization.
      operationId: updateCurrentOrganization
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateOrganizationRequest"
      responses:
        "200":
          description: Organization updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Organization"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: Owner or admin role required.
  /v1/organizations/current/members/{userId}:
    patch:
      tags: [Organizations]
      summary: Change an organization member role.
      operationId: updateOrganizationMember
      parameters:
        - $ref: "#/components/parameters/UserId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateOrganizationMemberRequest"
      responses:
        "200":
          description: Member updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationMember"
        "403":
          description: Insufficient organization role.
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      tags: [Organizations]
      summary: Remove an organization member.
      operationId: removeOrganizationMember
      parameters:
        - $ref: "#/components/parameters/UserId"
      responses:
        "200":
          description: Member removed.
        "403":
          description: Insufficient organization role.
        "404":
          $ref: "#/components/responses/NotFound"
        "409":
          description: Cannot remove the last owner.
  /v1/organizations/current/invitations:
    get:
      tags: [Organizations]
      summary: List organization invitations.
      operationId: listOrganizationInvitations
      responses:
        "200":
          description: Invitation list.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationInvitationListResponse"
        "403":
          description: Owner or admin role required.
    post:
      tags: [Organizations]
      summary: Create a team invitation.
      operationId: createOrganizationInvitation
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateOrganizationInvitationRequest"
      responses:
        "201":
          description: Invitation created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/OrganizationInvitation"
        "403":
          description: Owner or admin role required.
        "409":
          description: Existing member or pending invitation.
  /v1/invitations/{token}/accept:
    post:
      tags: [Organizations]
      summary: Accept a team invitation.
      operationId: acceptOrganizationInvitation
      parameters:
        - $ref: "#/components/parameters/InvitationToken"
      responses:
        "200":
          description: Invitation accepted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/InvitationPreviewResponse"
        "409":
          description: Invitation is expired, used, revoked, or does not match the signed-in user.
  /v1/clusters:
    get:
      tags: [Clusters]
      summary: List infrastructure clusters.
      operationId: listClusters
      responses:
        "200":
          description: Cluster list.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ClusterListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      tags: [Clusters]
      summary: Create an infrastructure cluster.
      operationId: createCluster
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateClusterRequest"
      responses:
        "201":
          description: Cluster created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Cluster"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/clusters/{clusterId}:
    get:
      tags: [Clusters]
      summary: Get an infrastructure cluster.
      operationId: getCluster
      parameters:
        - $ref: "#/components/parameters/ClusterId"
      responses:
        "200":
          description: Cluster detail.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Cluster"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    patch:
      tags: [Clusters]
      summary: Update mutable cluster fields.
      operationId: updateCluster
      parameters:
        - $ref: "#/components/parameters/ClusterId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateClusterRequest"
      responses:
        "200":
          description: Cluster updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Cluster"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/integration-catalog:
    get:
      tags: [Integrations]
      summary: List integration extensions visible to the tenant.
      operationId: listIntegrationCatalog
      responses:
        "200":
          description: Integration catalog.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationCatalogListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/integration-catalog/{extensionKey}:
    get:
      tags: [Integrations]
      summary: Show one integration catalog entry.
      operationId: getIntegrationCatalogItem
      parameters:
        - $ref: "#/components/parameters/ExtensionKey"
      responses:
        "200":
          description: Integration catalog item.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationCatalogItem"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/integration-installs:
    get:
      tags: [Integrations]
      summary: List integrations installed in the current tenant.
      operationId: listIntegrationInstalls
      responses:
        "200":
          description: Tenant integration installs.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationInstallListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/integration-installs/{extensionKey}:
    post:
      tags: [Integrations]
      summary: Install one integration extension into the tenant.
      operationId: installIntegration
      parameters:
        - $ref: "#/components/parameters/ExtensionKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/IntegrationInstallRequest"
      responses:
        "201":
          description: Integration installed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationInstallResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/integration-installs/{extensionKey}/settings:
    get:
      tags: [Integrations]
      summary: Show requested and effective settings for an installed integration.
      operationId: getIntegrationSettings
      parameters:
        - $ref: "#/components/parameters/ExtensionKey"
      responses:
        "200":
          description: Integration settings.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationSettingsResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    patch:
      tags: [Integrations]
      summary: Update tenant-level settings for an installed integration.
      operationId: updateIntegrationSettings
      parameters:
        - $ref: "#/components/parameters/ExtensionKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/IntegrationSettingsUpdateRequest"
      responses:
        "200":
          description: Integration settings updated.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationSettingsResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/integration-installs/{extensionKey}/cli:
    get:
      tags: [Integrations]
      summary: Show CLI command metadata for an installed integration.
      operationId: getIntegrationCliCommands
      parameters:
        - $ref: "#/components/parameters/ExtensionKey"
      responses:
        "200":
          description: Extension CLI command metadata.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationCliResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/integration-extensions/{extensionKey}/invoke:
    post:
      tags: [Integrations]
      summary: Invoke an installed extension operation through the broker.
      operationId: invokeIntegrationExtension
      parameters:
        - $ref: "#/components/parameters/ExtensionKey"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExtensionOperationRequest"
      responses:
        "200":
          description: Extension operation completed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExtensionOperationResponse"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          description: Extension install, consent, or permission denied.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "409":
          description: Extension or target agent capabilities are incompatible.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "502":
          description: Extension execution failed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
        "503":
          description: Extension runtime is not configured.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/Error"
  /v1/integrations:
    get:
      tags: [Integrations]
      summary: List connected provider accounts.
      operationId: listIntegrations
      responses:
        "200":
          description: Provider integration accounts.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/IntegrationListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/data-plane/instances:
    get:
      tags: [Data Plane]
      summary: List managed data-plane instances.
      operationId: listDataPlaneInstances
      responses:
        "200":
          description: Data-plane instances.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataPlaneInstanceListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      tags: [Data Plane]
      summary: Create a managed data-plane instance through an installed extension.
      operationId: createDataPlaneInstance
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DataPlaneInstanceCreateRequest"
      responses:
        "201":
          description: Data-plane instance created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataPlaneInstance"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/data-plane/instances/{dataPlaneInstanceId}:
    get:
      tags: [Data Plane]
      summary: Show one managed data-plane instance.
      operationId: getDataPlaneInstance
      parameters:
        - $ref: "#/components/parameters/DataPlaneInstanceId"
      responses:
        "200":
          description: Data-plane instance.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataPlaneInstance"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      tags: [Data Plane]
      summary: Drain a managed data-plane instance.
      operationId: deleteDataPlaneInstance
      parameters:
        - $ref: "#/components/parameters/DataPlaneInstanceId"
      responses:
        "200":
          description: Data-plane instance marked draining.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DataPlaneInstance"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/object-stores:
    get:
      tags: [Data Plane]
      summary: List object-store resources.
      operationId: listObjectStores
      responses:
        "200":
          description: Object stores.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ObjectStoreListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      tags: [Data Plane]
      summary: Create an object-store resource.
      operationId: createObjectStore
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ObjectStoreCreateRequest"
      responses:
        "201":
          description: Object store created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ObjectStore"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/object-stores/{objectStoreId}:
    get:
      tags: [Data Plane]
      summary: Show one object-store resource.
      operationId: getObjectStore
      parameters:
        - $ref: "#/components/parameters/ObjectStoreId"
      responses:
        "200":
          description: Object store.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ObjectStore"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    delete:
      tags: [Data Plane]
      summary: Delete an object-store resource.
      operationId: deleteObjectStore
      parameters:
        - $ref: "#/components/parameters/ObjectStoreId"
      responses:
        "200":
          description: Object store marked deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ObjectStore"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "403":
          $ref: "#/components/responses/Forbidden"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/developer/apps:
    get:
      tags: [Integrations]
      summary: List developer apps owned by the current tenant.
      operationId: listDeveloperApps
      responses:
        "200":
          description: Developer apps.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeveloperAppListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
    post:
      tags: [Integrations]
      summary: Register a developer publisher app.
      operationId: createDeveloperApp
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/DeveloperAppCreateRequest"
      responses:
        "201":
          description: Developer app created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/DeveloperApp"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
  /v1/developer/apps/{developerAppId}/packages:
    get:
      tags: [Integrations]
      summary: List extension packages for a developer app.
      operationId: listExtensionPackages
      parameters:
        - $ref: "#/components/parameters/DeveloperAppId"
      responses:
        "200":
          description: Extension packages.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExtensionPackageListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    post:
      tags: [Integrations]
      summary: Create an extension package under a developer app.
      operationId: createExtensionPackage
      parameters:
        - $ref: "#/components/parameters/DeveloperAppId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExtensionPackageCreateRequest"
      responses:
        "201":
          description: Extension package created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExtensionPackage"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
  /v1/developer/packages/{extensionPackageId}/releases:
    get:
      tags: [Integrations]
      summary: List releases for an extension package.
      operationId: listExtensionReleases
      parameters:
        - $ref: "#/components/parameters/ExtensionPackageId"
      responses:
        "200":
          description: Extension releases.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExtensionReleaseListResponse"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
    post:
      tags: [Integrations]
      summary: Create a private, submitted, beta, or published extension release.
      operationId: createExtensionRelease
      parameters:
        - $ref: "#/components/parameters/ExtensionPackageId"
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ExtensionReleaseCreateRequest"
      responses:
        "201":
          description: Extension release created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ExtensionRelease"
        "400":
          $ref: "#/components/responses/BadRequest"
        "401":
          $ref: "#/components/responses/Unauthorized"
        "404":
          $ref: "#/components/responses/NotFound"
components:
  securitySchemes:
    cookieAuth:
      type: apiKey
      in: cookie
      name: globalstacks_session
  parameters:
    ClusterId:
      name: clusterId
      in: path
      required: true
      schema:
        type: string
    ExtensionKey:
      name: extensionKey
      in: path
      required: true
      schema:
        type: string
    DeveloperAppId:
      name: developerAppId
      in: path
      required: true
      schema:
        type: string
    DataPlaneInstanceId:
      name: dataPlaneInstanceId
      in: path
      required: true
      schema:
        type: string
    ObjectStoreId:
      name: objectStoreId
      in: path
      required: true
      schema:
        type: string
    ExtensionPackageId:
      name: extensionPackageId
      in: path
      required: true
      schema:
        type: string
    OrganizationId:
      name: organizationId
      in: path
      required: true
      schema:
        type: string
    UserId:
      name: userId
      in: path
      required: true
      schema:
        type: string
    InvitationToken:
      name: token
      in: path
      required: true
      schema:
        type: string
  responses:
    BadRequest:
      description: Invalid request payload.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Unauthorized:
      description: Authentication required or session invalid.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    Forbidden:
      description: Authenticated principal is not allowed to perform this operation.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
    NotFound:
      description: Resource not found.
      content:
        application/json:
          schema:
            $ref: "#/components/schemas/Error"
  schemas:
    Error:
      type: object
      additionalProperties: false
      required: [message]
      properties:
        message:
          type: string
    ObjectMeta:
      type: object
      additionalProperties: false
      required: [id, createdAt, updatedAt]
      properties:
        id:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    UserSummary:
      type: object
      additionalProperties: false
      required: [id, email, displayName]
      properties:
        id:
          type: string
        email:
          type: string
          format: email
        displayName:
          type: string
    SessionResponse:
      type: object
      additionalProperties: false
      required: [authenticated]
      properties:
        authenticated:
          type: boolean
        sessionId:
          type: string
        tenantId:
          type: string
        user:
          $ref: "#/components/schemas/UserSummary"
    CreateSessionRequest:
      type: object
      additionalProperties: false
      required: [strategy]
      properties:
        strategy:
          type: string
          enum: [password, oidc_device_code]
        loginName:
          type: string
        password:
          type: string
        provider:
          type: string
    Tenant:
      allOf:
        - $ref: "#/components/schemas/ObjectMeta"
        - type: object
          additionalProperties: false
          required: [name, slug]
          properties:
            name:
              type: string
            slug:
              type: string
            description:
              type: string
    TenantListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/Tenant"
    CreateTenantRequest:
      type: object
      additionalProperties: false
      required: [name, slug]
      properties:
        name:
          type: string
        slug:
          type: string
        description:
          type: string
    OrganizationRole:
      type: string
      enum: [owner, admin, member]
    Organization:
      allOf:
        - $ref: "#/components/schemas/ObjectMeta"
        - type: object
          additionalProperties: false
          required: [name, kind]
          properties:
            name:
              type: string
            slug:
              type: string
            kind:
              type: string
              enum: [personal, business]
            role:
              $ref: "#/components/schemas/OrganizationRole"
            active:
              type: boolean
    OrganizationListResponse:
      type: object
      additionalProperties: false
      required: [activeOrganizationId, items]
      properties:
        activeOrganizationId:
          type: string
        items:
          type: array
          items:
            $ref: "#/components/schemas/Organization"
    CreateOrganizationRequest:
      type: object
      additionalProperties: false
      required: [name]
      properties:
        name:
          type: string
    UpdateOrganizationRequest:
      type: object
      additionalProperties: false
      required: [name]
      properties:
        name:
          type: string
    OrganizationMember:
      type: object
      additionalProperties: false
      required: [userId, role, status, createdAt, updatedAt]
      properties:
        userId:
          type: string
        email:
          type: string
          format: email
        displayName:
          type: string
        role:
          $ref: "#/components/schemas/OrganizationRole"
        status:
          type: string
          enum: [active, removed]
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    UpdateOrganizationMemberRequest:
      type: object
      additionalProperties: false
      required: [role]
      properties:
        role:
          $ref: "#/components/schemas/OrganizationRole"
    OrganizationInvitation:
      type: object
      additionalProperties: false
      required: [id, email, role, status, expiresAt, createdAt, updatedAt]
      properties:
        id:
          type: string
        email:
          type: string
          format: email
        role:
          $ref: "#/components/schemas/OrganizationRole"
        status:
          type: string
          enum: [pending, accepted, revoked, expired]
        tokenPrefix:
          type: string
        acceptUrl:
          type: string
        expiresAt:
          type: string
          format: date-time
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    OrganizationInvitationListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/OrganizationInvitation"
    CreateOrganizationInvitationRequest:
      type: object
      additionalProperties: false
      required: [email, role]
      properties:
        email:
          type: string
          format: email
        role:
          $ref: "#/components/schemas/OrganizationRole"
    CurrentOrganizationResponse:
      type: object
      additionalProperties: false
      required: [organization, members, invitations, currentRole]
      properties:
        organization:
          $ref: "#/components/schemas/Organization"
        members:
          type: array
          items:
            $ref: "#/components/schemas/OrganizationMember"
        invitations:
          type: array
          items:
            $ref: "#/components/schemas/OrganizationInvitation"
        currentRole:
          $ref: "#/components/schemas/OrganizationRole"
    InvitationPreviewResponse:
      type: object
      additionalProperties: false
      required: [organization, invitation]
      properties:
        organization:
          $ref: "#/components/schemas/Organization"
        invitation:
          $ref: "#/components/schemas/OrganizationInvitation"
    Integration:
      allOf:
        - $ref: "#/components/schemas/ObjectMeta"
        - type: object
          additionalProperties: false
          required: [provider, kind, name, status]
          properties:
            provider:
              type: string
            kind:
              type: string
            name:
              type: string
            status:
              type: string
              enum: [connected, needs_reauth, disabled, deleted]
            externalAccountId:
              type: string
            metadata:
              type: object
              additionalProperties: true
    IntegrationListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/Integration"
    IntegrationCatalogItem:
      type: object
      additionalProperties: false
      required:
        - extensionKey
        - name
        - description
        - provider
        - publisher
        - version
        - releaseStatus
        - visibility
        - installedStatus
        - consentState
        - compatibilityStatus
        - permissions
        - egress
        - artifactDigest
        - manifestDigest
        - brokerProtocol
        - agentCapabilities
      properties:
        extensionKey:
          type: string
        name:
          type: string
        description:
          type: string
        provider:
          type: string
        publisher:
          type: string
        author:
          type: string
        category:
          type: string
        tags:
          type: array
          items:
            type: string
        version:
          type: string
        releaseStatus:
          type: string
          enum: [draft, private, submitted, approved, beta, published, rejected, revoked]
        visibility:
          type: string
          enum: [private, allowlisted, beta, public]
        installedStatus:
          type: string
        installedVersion:
          type: string
        updateAvailable:
          type: boolean
        consentState:
          type: string
        compatibilityStatus:
          type: string
        missingRequirements:
          type: array
          items:
            type: string
        permissions:
          type: array
          items:
            type: string
        egress:
          type: array
          items:
            type: string
        artifactDigest:
          type: string
        manifestDigest:
          type: string
        brokerProtocol:
          type: string
        agentCapabilities:
          type: array
          items:
            type: string
        homepageUrl:
          type: string
        repositoryUrl:
          type: string
        supportUrl:
          type: string
        termsUrl:
          type: string
        privacyUrl:
          type: string
    IntegrationCatalogListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/IntegrationCatalogItem"
    IntegrationInstall:
      allOf:
        - $ref: "#/components/schemas/ObjectMeta"
        - type: object
          additionalProperties: false
          required: [extensionKey, extensionId, version, status]
          properties:
            extensionKey:
              type: string
            extensionId:
              type: string
            version:
              type: string
            status:
              type: string
              enum: [installed, needs_reconsent, upgrade_required, unsupported, disabled]
            consentVersion:
              type: string
            installedBy:
              type: string
            settings:
              type: object
              additionalProperties: true
              description: Tenant-level requested extension settings.
            effectiveSettings:
              type: object
              additionalProperties: true
              description: Manifest defaults, tenant settings, and control-plane policy resolved into effective settings.
    IntegrationInstallListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/IntegrationInstall"
    IntegrationInstallRequest:
      type: object
      additionalProperties: false
      required: [manifest_digest, artifact_digest]
      properties:
        manifest_digest:
          type: string
          description: Manifest digest shown on the consent screen.
        artifact_digest:
          type: string
          description: Artifact digest shown on the consent screen.
        settings:
          type: object
          additionalProperties: true
          description: Optional tenant-level settings validated against the extension settings schema.
    IntegrationInstallResponse:
      type: object
      additionalProperties: false
      required: [catalogItem, install]
      properties:
        catalogItem:
          $ref: "#/components/schemas/IntegrationCatalogItem"
        install:
          $ref: "#/components/schemas/IntegrationInstall"
    IntegrationSettingsResponse:
      type: object
      additionalProperties: false
      required: [extensionKey, settings, effectiveSettings]
      properties:
        extensionKey:
          type: string
        settings:
          type: object
          additionalProperties: true
          description: Tenant-level requested extension settings.
        effectiveSettings:
          type: object
          additionalProperties: true
          description: Resolved settings after manifest defaults and control-plane policy.
        mutation:
          type: object
          additionalProperties:
            type: array
            items:
              type: string
          description: Settings grouped by mutable, requires_reconcile, and immutable classes.
    IntegrationSettingsUpdateRequest:
      type: object
      additionalProperties: false
      required: [settings]
      properties:
        settings:
          type: object
          additionalProperties: true
          description: Tenant-level settings patch or replacement validated against the extension settings schema.
    IntegrationCliResponse:
      type: object
      additionalProperties: false
      required: [extensionKey, commands]
      properties:
        extensionKey:
          type: string
        commands:
          type: array
          items:
            $ref: "#/components/schemas/IntegrationCliCommand"
    IntegrationCliCommand:
      type: object
      additionalProperties: true
      required: [path, operation]
      properties:
        path:
          type: array
          items:
            type: string
        operation:
          type: string
        short:
          type: string
        targetKind:
          type: string
        targetId:
          type: string
        output:
          type: string
          enum: [json, table, passthrough]
        args:
          type: array
          items:
            type: object
            additionalProperties: true
        flags:
          type: array
          items:
            type: object
            additionalProperties: true
    ExtensionOperationRequest:
      type: object
      additionalProperties: false
      required: [operation, targetKind, targetId]
      properties:
        operation:
          type: string
          examples: [cloudflare-r2.bucket.create]
        targetKind:
          type: string
          examples: [cluster]
        targetId:
          type: string
        integrationId:
          type: string
        input:
          type: object
          additionalProperties: true
    ExtensionOperationResponse:
      type: object
      additionalProperties: false
      required: [jobId, status]
      properties:
        jobId:
          type: string
        status:
          type: string
          enum: [succeeded]
        outputs:
          type: object
          additionalProperties: true
        diagnostics:
          type: array
          items:
            type: string
    DataPlaneInstance:
      type: object
      additionalProperties: false
      required: [id, provider, extensionKey, hostId, state, createdAt, updatedAt]
      properties:
        id:
          type: string
        provider:
          type: string
        extensionKey:
          type: string
        extensionInstallId:
          type: string
        hostId:
          type: string
        state:
          type: string
          enum: [provisioning, healthy, degraded, failed, draining, deleted]
        endpoint:
          type: string
        settings:
          type: object
          additionalProperties: true
        effectiveSettings:
          type: object
          additionalProperties: true
        health:
          type: object
          additionalProperties: true
        metadata:
          type: object
          additionalProperties: true
        createdBy:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    DataPlaneInstanceListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/DataPlaneInstance"
    DataPlaneInstanceCreateRequest:
      type: object
      additionalProperties: false
      required: [extensionKey, hostId]
      properties:
        provider:
          type: string
        extensionKey:
          type: string
        hostId:
          type: string
        settings:
          type: object
          additionalProperties: true
    ObjectStore:
      type: object
      additionalProperties: false
      required: [id, providerKey, hostedMode, purpose, bucket, status, createdAt, updatedAt]
      properties:
        id:
          type: string
        providerKey:
          type: string
        hostedMode:
          type: string
          enum: [external, customer_managed, globalstacks_managed]
        purpose:
          type: string
          enum: [volume_data, metadata_backup, artifact_cache, logs]
        endpoint:
          type: string
        bucket:
          type: string
        prefix:
          type: string
        credentialRef:
          type: string
        dataPlaneInstanceId:
          type: string
        status:
          type: string
          enum: [provisioning, ready, degraded, failed, deleted]
        metadata:
          type: object
          additionalProperties: true
        createdBy:
          type: string
        createdAt:
          type: string
          format: date-time
        updatedAt:
          type: string
          format: date-time
    ObjectStoreListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/ObjectStore"
    ObjectStoreCreateRequest:
      type: object
      additionalProperties: false
      required: [providerKey, purpose, bucket]
      properties:
        providerKey:
          type: string
        hostedMode:
          type: string
          enum: [external, customer_managed, globalstacks_managed]
        purpose:
          type: string
          enum: [volume_data, metadata_backup, artifact_cache, logs]
        bucket:
          type: string
        prefix:
          type: string
        dataPlaneInstanceId:
          type: string
        metadata:
          type: object
          additionalProperties: true
    DeveloperApp:
      allOf:
        - $ref: "#/components/schemas/ObjectMeta"
        - type: object
          additionalProperties: false
          required: [name, publisherName, status]
          properties:
            name:
              type: string
            publisherName:
              type: string
            publisherUrl:
              type: string
            supportUrl:
              type: string
            termsUrl:
              type: string
            privacyUrl:
              type: string
            status:
              type: string
              enum: [draft, active, suspended]
            createdBy:
              type: string
    DeveloperAppCreateRequest:
      type: object
      additionalProperties: false
      required: [name, publisherName, supportUrl, termsUrl, privacyUrl]
      properties:
        name:
          type: string
        publisherName:
          type: string
        publisherUrl:
          type: string
        supportUrl:
          type: string
        termsUrl:
          type: string
        privacyUrl:
          type: string
    DeveloperAppListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/DeveloperApp"
    ExtensionPackage:
      allOf:
        - $ref: "#/components/schemas/ObjectMeta"
        - type: object
          additionalProperties: false
          required: [developerAppId, extensionKey, name, status]
          properties:
            developerAppId:
              type: string
            extensionKey:
              type: string
            name:
              type: string
            description:
              type: string
            category:
              type: string
            tags:
              type: array
              items:
                type: string
            status:
              type: string
              enum: [draft, active, suspended, archived]
    ExtensionPackageCreateRequest:
      type: object
      additionalProperties: false
      required: [extensionKey, name]
      properties:
        extensionKey:
          type: string
        name:
          type: string
        description:
          type: string
        category:
          type: string
        tags:
          type: array
          items:
            type: string
    ExtensionPackageListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/ExtensionPackage"
    ExtensionRelease:
      allOf:
        - $ref: "#/components/schemas/ObjectMeta"
        - type: object
          additionalProperties: false
          required: [extensionPackageId, version, artifactDigest, manifestDigest, releaseStatus, visibility]
          properties:
            extensionPackageId:
              type: string
            version:
              type: string
            artifactDigest:
              type: string
            manifestDigest:
              type: string
            permissions:
              type: array
              items:
                type: string
            egress:
              type: array
              items:
                type: string
            brokerProtocol:
              type: string
            minGlobalstacksVersion:
              type: string
            agentCapabilities:
              type: array
              items:
                type: string
            releaseStatus:
              type: string
              enum: [draft, private, submitted, approved, beta, published, rejected, revoked]
            visibility:
              type: string
              enum: [private, allowlisted, beta, public]
            submittedAt:
              type: string
              format: date-time
            reviewedAt:
              type: string
              format: date-time
            publishedAt:
              type: string
              format: date-time
    ExtensionReleaseCreateRequest:
      type: object
      additionalProperties: false
      required: [version, artifactDigest, manifestDigest]
      properties:
        version:
          type: string
        artifactDigest:
          type: string
        manifestDigest:
          type: string
        permissions:
          type: array
          items:
            type: string
        egress:
          type: array
          items:
            type: string
        brokerProtocol:
          type: string
        minGlobalstacksVersion:
          type: string
        agentCapabilities:
          type: array
          items:
            type: string
    ExtensionReleaseListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/ExtensionRelease"
    ClusterOwnership:
      type: string
      enum: [byo, globalstacks-managed]
    Cluster:
      allOf:
        - $ref: "#/components/schemas/ObjectMeta"
        - type: object
          additionalProperties: false
          required: [name, slug, ownership, provider, status]
          properties:
            name:
              type: string
            slug:
              type: string
            ownership:
              $ref: "#/components/schemas/ClusterOwnership"
            provider:
              type: string
              examples: [self-hosted, globalstacks, aws]
            status:
              type: string
              enum: [active, provisioning, paused, archived]
            metadata:
              type: object
              additionalProperties:
                type: string
    ClusterListResponse:
      type: object
      additionalProperties: false
      required: [items]
      properties:
        items:
          type: array
          items:
            $ref: "#/components/schemas/Cluster"
    CreateClusterRequest:
      type: object
      additionalProperties: false
      required: [name, ownership]
      properties:
        name:
          type: string
        slug:
          type: string
        ownership:
          $ref: "#/components/schemas/ClusterOwnership"
        provider:
          type: string
        metadata:
          type: object
          additionalProperties:
            type: string
    UpdateClusterRequest:
      type: object
      additionalProperties: false
      properties:
        name:
          type: string
        status:
          type: string
          enum: [active, provisioning, paused, archived]
        metadata:
          type: object
          additionalProperties:
            type: string
