openapi: 3.0.0
paths:
  /api/health:
    get:
      description: Retrieves the current health of the app. If the app is running and
        it is connected to the database it always returns an empty 200 OK
      operationId: HealthController_getHealth
      parameters: []
      responses:
        "200":
          description: The Health Check is successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - ok
                      - degraded
                    example: ok
                  info:
                    type: object
                    example: &a1
                      database:
                        status: up
                        responseTime: 12
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                          enum:
                            - up
                            - degraded
                            - down
                        responseTime:
                          type: number
                          description: Time the health indicator took to respond, in ms
                      additionalProperties: true
                    nullable: true
                  error:
                    type: object
                    example: {}
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                          enum:
                            - up
                            - degraded
                            - down
                        responseTime:
                          type: number
                          description: Time the health indicator took to respond, in ms
                      additionalProperties: true
                    nullable: true
                  details:
                    type: object
                    example: *a1
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                          enum:
                            - up
                            - degraded
                            - down
                        responseTime:
                          type: number
                          description: Time the health indicator took to respond, in ms
                      additionalProperties: true
        "502":
          description: ""
        "503":
          description: The Health Check is not successful
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - error
                      - shutting_down
                    example: error
                  info:
                    type: object
                    example:
                      database: &a2
                        status: up
                        responseTime: 12
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                          enum:
                            - up
                            - degraded
                            - down
                        responseTime:
                          type: number
                          description: Time the health indicator took to respond, in ms
                      additionalProperties: true
                    nullable: true
                  error:
                    type: object
                    example:
                      redis: &a3
                        status: down
                        message: Could not connect
                        responseTime: 3005
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                          enum:
                            - up
                            - degraded
                            - down
                        responseTime:
                          type: number
                          description: Time the health indicator took to respond, in ms
                      additionalProperties: true
                    nullable: true
                  details:
                    type: object
                    example:
                      database: *a2
                      redis: *a3
                    additionalProperties:
                      type: object
                      required:
                        - status
                      properties:
                        status:
                          type: string
                          enum:
                            - up
                            - degraded
                            - down
                        responseTime:
                          type: number
                          description: Time the health indicator took to respond, in ms
                      additionalProperties: true
      summary: Health check
      tags:
        - Health
  /api/capabilities:
    get:
      operationId: TenantManagementController_capabilities
      parameters: []
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/tenants:
    get:
      operationId: TenantManagementController_list
      parameters: []
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
    post:
      operationId: TenantManagementController_create
      parameters:
        - name: idempotency-key
          required: true
          in: header
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateManagedTenantDto"
      responses:
        "202":
          description: Canonical identity reserved; operation continues durably
      tags:
        - Tenant Management
  /api/imports:
    post:
      operationId: TenantManagementController_import
      parameters:
        - name: idempotency-key
          required: true
          in: header
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ImportManagedTenantDto"
      responses:
        "202":
          description: ""
      tags:
        - Tenant Management
  /api/platform/accounts/lookup:
    get:
      operationId: TenantManagementController_lookupSsoAccount
      parameters:
        - name: username
          required: true
          in: query
          schema:
            type: string
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/platform/tenants:
    post:
      operationId: TenantManagementController_createForPlatform
      parameters:
        - name: idempotency-key
          required: true
          in: header
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePlatformManagedTenantDto"
      responses:
        "202":
          description: Operator-provisioned tenant continues through durable work
      tags:
        - Tenant Management
  /api/tenants/{id}:
    get:
      operationId: TenantManagementController_get
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
    patch:
      operationId: TenantManagementController_rename
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/RenameTenantDto"
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/accounts:
    post:
      operationId: TenantManagementController_addAccount
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: idempotency-key
          required: true
          in: header
          schema:
            type: string
        - name: Idempotency-Key
          in: header
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AddManagedTenantAccountDto"
      responses:
        "202":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/accounts/{principalId}/setup-link:
    post:
      operationId: TenantManagementController_setupAccountLink
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: principalId
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TenantRevisionDto"
      responses:
        "201":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/operations:
    get:
      operationId: TenantManagementController_operations
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/operations/{id}:
    get:
      operationId: TenantManagementController_operation
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/operations/{id}/retry:
    post:
      operationId: TenantManagementController_retryOperation
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        "201":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/members:
    put:
      operationId: TenantManagementController_member
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagedMemberDto"
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/ownership-transfer:
    post:
      operationId: TenantManagementController_transfer
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TransferOwnerDto"
      responses:
        "201":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/grants:
    put:
      operationId: TenantManagementController_grant
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagedGrantDto"
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/grants/recover-owner:
    post:
      operationId: TenantManagementController_recoverOwnerGrants
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TenantRevisionDto"
      responses:
        "201":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/lifecycle:
    put:
      operationId: TenantManagementController_lifecycle
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagedLifecycleDto"
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/invitations:
    post:
      operationId: TenantManagementController_invite
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/ManagedInvitationDto"
      responses:
        "201":
          description: ""
      tags:
        - Tenant Management
    get:
      operationId: TenantManagementController_invitations
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/invitations/accept:
    post:
      operationId: TenantManagementController_accept
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/AcceptInvitationDto"
      responses:
        "201":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/audit:
    get:
      operationId: TenantManagementController_audit
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/credentials/rotate:
    post:
      operationId: TenantManagementController_rotate
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TenantRevisionDto"
      responses:
        "201":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/configuration/reconcile:
    post:
      operationId: TenantManagementController_reconcileConfiguration
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TenantRevisionDto"
      responses:
        "202":
          description: ""
      tags:
        - Tenant Management
  /api/tenants/{id}/invitations/{invitationId}:
    delete:
      operationId: TenantManagementController_revokeInvitation
      parameters:
        - name: id
          required: true
          in: path
          schema:
            type: string
        - name: invitationId
          required: true
          in: path
          schema:
            type: string
      responses:
        "200":
          description: ""
      tags:
        - Tenant Management
  /api/auth/tenancy:
    get:
      operationId: AuthController_tenancyInfo
      parameters: []
      responses:
        "200":
          description: ""
      tags:
        - Authentication
  /api/auth/user:
    get:
      description: Retrieves current user state, whether someone is logged in or not a
        200 result is provided. This is used in the frontend to determine
        whether certain aspects should be shown.
      operationId: AuthController_getUser
      parameters: []
      responses:
        "200":
          description: ""
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: "#/components/schemas/AuthenticatedUser"
                  - $ref: "#/components/schemas/UnauthenticatedUser"
      summary: Retrieve current user status
      tags:
        - Authentication
  /api/auth/login:
    get:
      description: Redirects to the authorization server, preserving a safe return
        route and optional OIDC prompt
      operationId: AuthController_login
      parameters:
        - name: tenant_id
          required: false
          in: query
          schema:
            type: string
        - name: return_to
          required: false
          in: query
          schema:
            type: string
        - name: prompt
          required: false
          in: query
          schema:
            type: string
      responses:
        "302":
          description: ""
      summary: Login redirect
      tags:
        - Authentication
  /api/auth/logout:
    get:
      description: Removes session information and redirects to a safe same-origin
        return route or the configured UI root
      operationId: AuthController_logout
      parameters:
        - name: return_to
          required: false
          in: query
          schema:
            type: string
      responses:
        "302":
          description: ""
      summary: Logout redirect
      tags:
        - Authentication
  /api/auth/callback:
    get:
      description: Users are redirected from the authorization server to this endpoint
        which will redirect them to the frontend (`auth.redirectURL`)
      operationId: AuthController_callback
      parameters:
        - name: state
          required: false
          in: query
          description: The state parameter
          schema:
            example: randomState
            type: string
        - name: code
          required: false
          in: query
          description: The authorization code
          schema:
            example: code
            type: string
        - name: access_token
          required: false
          in: query
          description: The access token
          schema:
            type: string
        - name: token_type
          required: false
          in: query
          description: The token type
          schema:
            example: Bearer
            type: string
        - name: expires_in
          required: false
          in: query
          description: The token expiration in seconds
          schema:
            example: 3600
            type: string
        - name: id_token
          required: false
          in: query
          description: The ID token
          schema:
            type: string
        - name: code_verifier
          required: false
          in: query
          description: The code verifier
          schema:
            example: randomChallengeVerifier
            type: string
      responses:
        "302":
          description: ""
      summary: Login callback
      tags:
        - Authentication
info:
  title: TSG Tenant Management
  description: ""
  version: "1"
  contact: {}
tags: []
servers: []
components:
  securitySchemes:
    bearer:
      scheme: bearer
      bearerFormat: JWT
      type: http
  schemas:
    CreateManagedTenantDto:
      type: object
      properties:
        name:
          type: string
        slug:
          type: string
          description: Immutable URL name, never reused
        profile:
          type: string
          description: Operator-registered service profile
      required:
        - name
        - slug
        - profile
    PrincipalDto:
      type: object
      properties:
        issuer:
          type: string
        subject:
          type: string
      required:
        - issuer
        - subject
    ImportedMembershipDto:
      type: object
      properties:
        tenantId:
          type: string
        principal:
          $ref: "#/components/schemas/PrincipalDto"
        role:
          type: string
          enum:
            - owner
            - admin
            - member
        status:
          type: string
          enum:
            - active
            - revoked
      required:
        - tenantId
        - principal
        - role
        - status
    ImportedGrantDto:
      type: object
      properties:
        tenantId:
          type: string
        principal:
          $ref: "#/components/schemas/PrincipalDto"
        serviceInstanceId:
          type: string
        permissions:
          type: array
          items:
            type: string
      required:
        - tenantId
        - principal
        - serviceInstanceId
        - permissions
    ImportedInvitationDto:
      type: object
      properties:
        tokenHash:
          type: string
          description: SHA-256 hex of the possession proof
        role:
          type: string
          enum:
            - admin
            - member
        principal:
          $ref: "#/components/schemas/PrincipalDto"
        expiresAt:
          type: number
          description: Expiry in epoch milliseconds
      required:
        - tokenHash
        - role
        - expiresAt
    ImportManagedTenantDto:
      type: object
      properties:
        name:
          type: string
        slug:
          type: string
          description: Immutable URL name, never reused
        profile:
          type: string
          description: Operator-registered service profile
        tenantId:
          type: string
        memberships:
          type: array
          items:
            $ref: "#/components/schemas/ImportedMembershipDto"
        grants:
          type: array
          items:
            $ref: "#/components/schemas/ImportedGrantDto"
        mappings:
          type: object
          additionalProperties:
            type: array
            items:
              type: object
        localTenantIds:
          type: object
          additionalProperties:
            type: string
        localTenantSlugs:
          type: object
          additionalProperties:
            type: string
        invitations:
          description: Pending invitations with SHA-256 possession-proof hashes, explicit
            roles/principals and epoch-millisecond expiry
          type: array
          items:
            $ref: "#/components/schemas/ImportedInvitationDto"
      required:
        - name
        - slug
        - profile
        - tenantId
        - memberships
        - grants
        - mappings
        - localTenantIds
        - localTenantSlugs
    ManagedAccountSelectorDto:
      type: object
      properties:
        kind:
          type: string
          enum:
            - existing
            - new
        principal:
          $ref: "#/components/schemas/PrincipalDto"
        username:
          type: string
        email:
          type: string
      required:
        - kind
    CreatePlatformManagedTenantDto:
      type: object
      properties:
        name:
          type: string
        slug:
          type: string
          description: Immutable URL name, never reused
        profile:
          type: string
          description: Operator-registered service profile
        owner:
          $ref: "#/components/schemas/ManagedAccountSelectorDto"
      required:
        - name
        - slug
        - profile
        - owner
    ManagedAccountGrantDto:
      type: object
      properties:
        serviceInstanceId:
          type: string
        permissions:
          type: array
          items:
            type: string
      required:
        - serviceInstanceId
        - permissions
    AddManagedTenantAccountDto:
      type: object
      properties:
        revision:
          type: number
          description: Current revision; stale writes conflict
        account:
          $ref: "#/components/schemas/ManagedAccountSelectorDto"
        role:
          type: string
          enum:
            - admin
            - member
        grants:
          type: array
          items:
            $ref: "#/components/schemas/ManagedAccountGrantDto"
      required:
        - revision
        - account
        - role
        - grants
    TenantRevisionDto:
      type: object
      properties:
        revision:
          type: number
          description: Current revision; stale writes conflict
      required:
        - revision
    RenameTenantDto:
      type: object
      properties:
        revision:
          type: number
          description: Current revision; stale writes conflict
        name:
          type: string
      required:
        - revision
        - name
    ManagedMemberDto:
      type: object
      properties:
        revision:
          type: number
          description: Current revision; stale writes conflict
        principal:
          $ref: "#/components/schemas/PrincipalDto"
        role:
          type: string
          enum:
            - admin
            - member
        status:
          type: string
          enum:
            - active
            - revoked
      required:
        - revision
        - principal
        - role
        - status
    TransferOwnerDto:
      type: object
      properties:
        revision:
          type: number
          description: Current revision; stale writes conflict
        principal:
          $ref: "#/components/schemas/PrincipalDto"
      required:
        - revision
        - principal
    ManagedGrantDto:
      type: object
      properties:
        revision:
          type: number
          description: Current revision; stale writes conflict
        principal:
          $ref: "#/components/schemas/PrincipalDto"
        serviceInstanceId:
          type: string
        permissions:
          type: array
          items:
            type: string
      required:
        - revision
        - principal
        - serviceInstanceId
        - permissions
    ManagedLifecycleDto:
      type: object
      properties:
        revision:
          type: number
          description: Current revision; stale writes conflict
        state:
          type: string
          enum:
            - active
            - suspended
            - deleting
      required:
        - revision
        - state
    ManagedInvitationDto:
      type: object
      properties:
        revision:
          type: number
          description: Current revision; stale writes conflict
        role:
          type: string
          enum:
            - admin
            - member
        principal:
          $ref: "#/components/schemas/PrincipalDto"
      required:
        - revision
        - role
    AcceptInvitationDto:
      type: object
      properties:
        token:
          type: string
          description: Explicit possession proof supplied by the invitee
      required:
        - token
    ClientInfo:
      type: object
      properties:
        issuer:
          type: string
        tenantId:
          type: string
        audience:
          oneOf:
            - type: string
            - type: array
              items:
                type: string
        actorType:
          type: string
          enum:
            - human
            - service
        authorizationRevision:
          type: number
        platformAdministrator:
          type: boolean
          description: Whether this human principal has operator-configured platform
            authority
        sub:
          type: string
          example: user-id-123
        name:
          type: string
          example: John Doe
        email:
          type: string
          example: john.doe@example.com
        didId:
          type: string
          example: did:example:123456789
        permissions:
          example:
            - read:credential:own
            - manage:key
          description: ABAC permissions
          type: array
          items:
            type: string
      required:
        - sub
        - name
        - email
        - permissions
    AuthenticatedUser:
      type: object
      properties:
        state:
          type: object
          example: authenticated
        user:
          example:
            sub: user-id-123
            name: John Doe
            email: john.doe@example.com
            permissions:
              - read:credential:own
              - manage:key
            didId: did:example:123456789
            platformAdministrator: false
          allOf:
            - $ref: "#/components/schemas/ClientInfo"
      required:
        - state
        - user
    UnauthenticatedUser:
      type: object
      properties:
        state:
          type: object
          example: unauthenticated
      required:
        - state
