openapi: 3.1.0
info:
  title: Qeet ID API
  version: 0.2.0
  description: The complete Qeet ID identity platform — authentication & access, identity management, federation, developer tooling and operations — in one reference.
servers:
  - url: https://api.id.qeet.in
    description: Production
  - url: https://api.id.staging.qeet.in
    description: Staging
  - url: http://localhost:4001
    description: Local (docker compose)
tags:
  - name: Auth
    description: Login, signup, refresh, sessions, hosted-login SSO cookie.
  - name: RBAC
    description: Roles, permissions, assignments, and authorization checks.
  - name: MFA
    description: TOTP and OTP (email/SMS) second factors plus recovery codes.
  - name: Passkeys
    description: WebAuthn passkey registration and passwordless login.
  - name: IP Rules
    description: Per-tenant IP allow/deny CIDR rules.
  - name: Auth Policy
    description: Per-tenant password rules and allowed login methods.
  - name: Policy
    description: Per-tenant security policy.
  - name: Threats
  - name: ReBAC
  - name: Users
    description: User CRUD, password set, and soft-delete recycle bin (restore/purge).
  - name: Tenants
    description: Tenant (workspace) CRUD.
  - name: Invites
    description: Tenant member invitations.
  - name: Groups
    description: User groups and membership.
  - name: Verification
    description: Email and phone verification flows.
  - name: Branding
    description: Per-tenant hosted-login branding.
  - name: Domains
  - name: OIDC
    description: 'OpenID Connect / OAuth 2.0 provider: discovery, authorize, token, userinfo, clients, grants, revocation, introspection, RP-initiated logout, and machine-to-machine service principals.'
  - name: SAML
    description: SAML 2.0 SSO — Qeet as Service Provider (consuming external IdPs) and as Identity Provider (serving downstream SPs).
  - name: SCIM
    description: SCIM 2.0 user/group provisioning (per-tenant bearer token presented by the IdP) plus tenant-admin token management.
  - name: Social
    description: Social/OAuth identity-provider login and account linking.
  - name: LDAP
    description: LDAP / Active Directory connection management and bind authentication.
  - name: API Keys
    description: Long-lived API keys for machine access.
  - name: Webhooks
    description: Outbound webhook endpoint management.
  - name: Secrets
    description: Per-tenant encrypted secrets vault.
  - name: Credentials
  - name: Agents
  - name: Auth Hooks
  - name: Audit
    description: Append-only, hash-chained audit log query and integrity verification.
  - name: GDPR
    description: Right-to-erasure purge requests.
  - name: Billing
    description: Subscription plans, subscriptions, and invoices.
  - name: Analytics
    description: Per-tenant usage analytics.
  - name: Email Templates
    description: Per-tenant transactional email template overrides.
  - name: Data Retention
    description: Per-tenant auto-purge of soft-deleted users.
  - name: Admin
    description: Operational/admin endpoints (outbox DLQ).
  - name: Health
    description: Liveness, readiness, and Prometheus metrics.
  - name: Rate Limits
    description: Per-tenant rate-limit overrides (tenant / user / API-key buckets).
  - name: Log Sinks
  - name: Notifications
x-tagGroups:
  - name: Authentication & Access
    tags:
      - Auth
      - RBAC
      - MFA
      - Passkeys
      - IP Rules
      - Auth Policy
      - Policy
      - Threats
      - ReBAC
  - name: Identity Management
    tags:
      - Users
      - Tenants
      - Invites
      - Groups
      - Verification
      - Branding
      - Domains
  - name: Federation
    tags:
      - OIDC
      - SAML
      - SCIM
      - Social
      - LDAP
  - name: Developer
    tags:
      - API Keys
      - Webhooks
      - Secrets
      - Credentials
      - Agents
      - Auth Hooks
  - name: Operations
    tags:
      - Audit
      - GDPR
      - Billing
      - Analytics
      - Email Templates
      - Data Retention
      - Admin
      - Health
      - Rate Limits
      - Log Sinks
      - Notifications
paths:
  /v1/auth/forgot-password:
    post:
      operationId: post_v1_auth_forgot_password
      summary: Forgot password
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
      responses:
        '200':
          description: Accepted (always, to avoid account enumeration); returns a neutral confirmation message
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/auth/login:
    post:
      operationId: post_v1_auth_login
      summary: Sign in
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
      responses:
        '200':
          description: |
            Either a full token pair (no MFA) or, when the user has a second
            factor enrolled, an MFA challenge `{mfa_required:true, mfa_token,
            methods[]}` to complete at POST /v1/auth/mfa.
          content:
            application/json:
              schema:
                oneOf:
                  - $ref: '#/components/schemas/TokenPair'
                  - type: object
                    properties:
                      mfa_required:
                        type: boolean
                      mfa_token:
                        type: string
                      methods:
                        type: array
                        items:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/auth/mfa:
    post:
      operationId: post_v1_auth_mfa
      summary: Complete MFA login
      description: Exchanges the mfa_token from /v1/auth/login plus a TOTP or recovery code for a token pair.
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - mfa_token
                - code
              properties:
                mfa_token:
                  type: string
                code:
                  type: string
                  description: A TOTP code or a one-time recovery code.
      responses:
        '200':
          description: Second factor verified; token pair issued
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenPair'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/auth/logout:
    post:
      operationId: post_v1_auth_logout
      summary: Logout
      tags:
        - Auth
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      responses:
        '200':
          description: Signed out
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/auth/magic-link/consume:
    post:
      operationId: post_v1_auth_magic_link_consume
      summary: Magic link consume
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - token
              properties:
                token:
                  type: string
      responses:
        '200':
          description: Token pair
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenPair'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/auth/magic-link/start:
    post:
      operationId: post_v1_auth_magic_link_start
      summary: Magic link start
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
              properties:
                email:
                  type: string
                  format: email
      responses:
        '200':
          description: Accepted (always, to avoid account enumeration); returns a neutral confirmation message
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/auth/me:
    get:
      operationId: get_v1_auth_me
      summary: Me
      tags:
        - Auth
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Current principal
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Principal'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/auth/refresh:
    post:
      operationId: post_v1_auth_refresh
      summary: Refresh
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RefreshRequest'
      responses:
        '200':
          description: Rotated token pair
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenPair'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/auth/reset-password:
    post:
      operationId: post_v1_auth_reset_password
      summary: Reset password
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - token
                - new_password
              properties:
                token:
                  type: string
                new_password:
                  type: string
                  minLength: 8
                  maxLength: 256
      responses:
        '200':
          description: Password reset; returns a confirmation message
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/auth/session:
    delete:
      operationId: delete_v1_auth_session
      summary: Destroy SSO session (logout)
      tags:
        - Auth
      security: []
      responses:
        '204':
          description: Session revoked, cookie cleared
    post:
      operationId: post_v1_auth_session
      summary: Create SSO session
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/LoginRequest'
      responses:
        '200':
          description: |
            Either the SSO cookie was set (`{user_id}`) or, when the user has a
            second factor enrolled, an MFA challenge `{mfa_required:true,
            mfa_token, methods[]}` to complete at POST /v1/auth/session/mfa
            (no cookie is set until then).
          content:
            application/json:
              schema:
                oneOf:
                  - type: object
                    properties:
                      user_id:
                        type: string
                        format: uuid
                  - type: object
                    properties:
                      mfa_required:
                        type: boolean
                      mfa_token:
                        type: string
                      methods:
                        type: array
                        items:
                          type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/auth/session/mfa:
    post:
      operationId: post_v1_auth_session_mfa
      summary: Complete SSO session MFA
      description: Exchanges the mfa_token from POST /v1/auth/session plus a TOTP or recovery code for the SSO cookie (qe_ls).
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - mfa_token
                - code
              properties:
                mfa_token:
                  type: string
                code:
                  type: string
                  description: A TOTP code or a one-time recovery code.
                remember:
                  type: boolean
                  description: Trust this device so future logins can skip the second factor (adaptive MFA). Honoured only when the tenant has enabled remember-device; sets the qe_td cookie.
      responses:
        '200':
          description: Second factor verified; SSO cookie set
          content:
            application/json:
              schema:
                type: object
                properties:
                  user_id:
                    type: string
                    format: uuid
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/auth/register:
    post:
      operationId: post_v1_auth_register
      summary: Register (hosted, B2C)
      description: |
        Creates a new end-user in the client's tenant and sets the SSO cookie
        (qe_ls) so they continue into the OAuth authorize flow. Gated by the
        tenant's self_registration_enabled policy (403 when disabled).
        Enumeration-safe: an existing email returns a neutral 422.
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - tenant_id
                - email
                - password
              properties:
                tenant_id:
                  type: string
                  format: uuid
                email:
                  type: string
                  format: email
                password:
                  type: string
                display_name:
                  type: string
      responses:
        '201':
          description: User created and SSO cookie set
          content:
            application/json:
              schema:
                type: object
                properties:
                  user_id:
                    type: string
                    format: uuid
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/auth/sessions:
    get:
      operationId: get_v1_auth_sessions
      summary: List sessions
      tags:
        - Auth
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Active sessions
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Session'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/auth/sessions/{id}:
    delete:
      operationId: delete_v1_auth_sessions_ById
      summary: Revoke session
      tags:
        - Auth
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Session revoked
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/auth/signup:
    post:
      operationId: post_v1_auth_signup
      summary: Sign up
      tags:
        - Auth
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SignupRequest'
      responses:
        '201':
          description: Created; token pair + user
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SignupResponse'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/auth/switch-tenant:
    post:
      operationId: post_v1_auth_switch_tenant
      summary: Switch tenant
      tags:
        - Auth
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - tenant_id
              properties:
                tenant_id:
                  type: string
                  format: uuid
      responses:
        '200':
          description: Token pair scoped to the target tenant
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenPair'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/check:
    get:
      operationId: get_v1_check
      summary: Permission check
      tags:
        - RBAC
      parameters:
        - in: query
          name: user_id
          required: true
          schema:
            type: string
            format: uuid
        - in: query
          name: tenant_id
          required: true
          schema:
            type: string
            format: uuid
        - in: query
          name: permission
          required: true
          schema:
            type: string
        - in: query
          name: explain
          required: false
          description: When "true", return the full authorization trace (allowed, the grant path(s), and a reason on denial) instead of the bare {allowed} object.
          schema:
            type: string
            enum:
              - 'true'
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Decision. The default shape is {allowed}. With explain=true the response is the Explanation object (allowed, paths, reason).
          content:
            application/json:
              schema:
                oneOf:
                  - type: object
                    properties:
                      allowed:
                        type: boolean
                  - $ref: '#/components/schemas/AuthzExplanation'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/mfa/otp/factors:
    get:
      operationId: get_v1_mfa_otp_factors
      summary: List OTP factors
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post_v1_mfa_otp_factors
      summary: Add OTP factor
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/otp/factors/{id}:
    delete:
      operationId: delete_v1_mfa_otp_factors_ById
      summary: Delete OTP factor
      tags:
        - MFA
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/otp/factors/{id}/challenge:
    post:
      operationId: post_v1_mfa_otp_factors_ById_challenge
      summary: Challenge OTP factor
      tags:
        - MFA
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/otp/factors/{id}/confirm:
    post:
      operationId: post_v1_mfa_otp_factors_ById_confirm
      summary: Confirm OTP factor
      tags:
        - MFA
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/otp/verify:
    post:
      operationId: post_v1_mfa_otp_verify
      summary: Verify OTP
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/recovery-codes:
    get:
      operationId: get_v1_mfa_recovery_codes
      summary: Recovery codes status
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/recovery-codes/regenerate:
    post:
      operationId: post_v1_mfa_recovery_codes_regenerate
      summary: Regenerate recovery codes (step-up)
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/step-up/status:
    get:
      operationId: get_v1_mfa_step_up_status
      summary: Step-up status
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Reports whether the principal completed a second-factor verification within the step-up window, and when.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/totp:
    delete:
      operationId: delete_v1_mfa_totp
      summary: Disable TOTP
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/totp/enroll/confirm:
    post:
      operationId: post_v1_mfa_totp_enroll_confirm
      summary: Confirm TOTP enrollment
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/totp/enroll/start:
    post:
      operationId: post_v1_mfa_totp_enroll_start
      summary: Start TOTP enrollment
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/totp/verify:
    post:
      operationId: post_v1_mfa_totp_verify
      summary: Verify TOTP
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/mfa/webauthn/challenge:
    post:
      operationId: post_v1_mfa_webauthn_challenge
      summary: WebAuthn 2FA challenge
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Starts a WebAuthn assertion ceremony over the authenticated user's existing passkey credentials, used as a second factor (no token is issued).
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '501':
          description: WebAuthn second factor not enabled
  /v1/mfa/webauthn/verify:
    post:
      operationId: post_v1_mfa_webauthn_verify
      summary: WebAuthn 2FA verify
      tags:
        - MFA
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Verifies a WebAuthn assertion against the user's registered credentials and records a step-up verification on success.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
        '501':
          description: WebAuthn second factor not enabled
  /v1/passkeys:
    get:
      operationId: get_v1_passkeys
      summary: List passkeys
      tags:
        - Passkeys
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/passkeys/login/begin:
    post:
      operationId: post_v1_passkeys_login_begin
      summary: Login begin
      tags:
        - Passkeys
      security: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/passkeys/login/finish:
    post:
      operationId: post_v1_passkeys_login_finish
      summary: Login finish
      tags:
        - Passkeys
      security: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/passkeys/register/begin:
    post:
      operationId: post_v1_passkeys_register_begin
      summary: Register begin
      tags:
        - Passkeys
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/passkeys/register/finish:
    post:
      operationId: post_v1_passkeys_register_finish
      summary: Register finish
      tags:
        - Passkeys
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/passkeys/{id}:
    delete:
      operationId: delete_v1_passkeys_ById
      summary: Delete passkey
      tags:
        - Passkeys
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/permissions:
    get:
      operationId: get_v1_permissions
      summary: List permissions
      tags:
        - RBAC
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Permissions
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Permission'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/roles/{roleID}/permissions/{permID}:
    delete:
      operationId: delete_v1_roles_ByRoleID_permissions_ByPermID
      summary: Revoke permission from role
      tags:
        - RBAC
      parameters:
        - name: roleID
          in: path
          required: true
          schema:
            type: string
        - name: permID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Revoked
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    post:
      operationId: post_v1_roles_ByRoleID_permissions_ByPermID
      summary: Grant permission to role
      tags:
        - RBAC
      parameters:
        - name: roleID
          in: path
          required: true
          schema:
            type: string
        - name: permID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      responses:
        '204':
          description: Granted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/auth-policy:
    get:
      operationId: get_v1_tenants_ByTenantID_auth_policy
      summary: Get auth policy
      tags:
        - Auth Policy
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put_v1_tenants_ByTenantID_auth_policy
      summary: Update auth policy
      tags:
        - Auth Policy
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/groups/{groupID}/roles:
    get:
      operationId: get_v1_tenants_ByTenantID_groups_ByGroupID_roles
      summary: List group roles
      tags:
        - RBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: groupID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Roles granted to the group
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/GroupRole'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/tenants/{tenantID}/groups/{groupID}/roles/{roleID}:
    post:
      operationId: post_v1_tenants_ByTenantID_groups_ByGroupID_roles_ByRoleID
      summary: Grant role to group
      description: Grant a role to a group. Every member of the group inherits the role's permissions (effective permissions = direct user grants UNION group-derived grants). The role and group must belong to the tenant.
      tags:
        - RBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: groupID
          in: path
          required: true
          schema:
            type: string
        - name: roleID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Granted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: delete_v1_tenants_ByTenantID_groups_ByGroupID_roles_ByRoleID
      summary: Revoke role from group
      tags:
        - RBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: groupID
          in: path
          required: true
          schema:
            type: string
        - name: roleID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Revoked
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/security/bots:
    get:
      operationId: get_v1_tenants_ByTenantID_security_bots
      summary: Bot telemetry
      tags:
        - Threats
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Recent bot verdicts and stats
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/tenants/{tenantID}/security/risk-settings:
    get:
      operationId: get_v1_tenants_ByTenantID_security_risk_settings
      summary: Get risk settings
      description: Returns the medium/high risk-score thresholds and the level at which step-up MFA is forced even for a trusted device.
      tags:
        - Threats
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Risk settings
          content:
            application/json:
              schema:
                type: object
                properties:
                  medium_threshold:
                    type: number
                  high_threshold:
                    type: number
                  force_mfa_at_level:
                    type: string
                    enum:
                      - medium
                      - high
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    put:
      operationId: put_v1_tenants_ByTenantID_security_risk_settings
      summary: Update risk settings
      tags:
        - Threats
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                medium_threshold:
                  type: number
                high_threshold:
                  type: number
                force_mfa_at_level:
                  type: string
                  enum:
                    - medium
                    - high
      responses:
        '200':
          description: Updated settings
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/security/bots/settings:
    get:
      operationId: get_v1_tenants_ByTenantID_security_bots_settings
      summary: Get bot settings
      tags:
        - Threats
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Bot-detection settings
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    put:
      operationId: put_v1_tenants_ByTenantID_security_bots_settings
      summary: Update bot settings
      tags:
        - Threats
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        '200':
          description: Updated settings
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/security/anomalies:
    get:
      operationId: get_v1_tenants_ByTenantID_security_anomalies
      summary: List anomalies
      tags:
        - Threats
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Recent anomalies
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/tenants/{tenantID}/security/anomalies/summary:
    get:
      operationId: get_v1_tenants_ByTenantID_security_anomalies_summary
      summary: Anomaly summary
      tags:
        - Threats
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Open/resolved/affected/high-severity counts
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/tenants/{tenantID}/security/anomalies/{id}/resolve:
    post:
      operationId: post_v1_tenants_ByTenantID_security_anomalies_ById_resolve
      summary: Resolve anomaly
      tags:
        - Threats
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Anomaly resolved
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/relation-tuples:
    get:
      operationId: get_v1_tenants_ByTenantID_relation_tuples
      summary: List relation tuples
      tags:
        - ReBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: object
          in: query
          required: true
          schema:
            type: string
          description: Object ref "type:id", e.g. document:readme
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Tuples on the object
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_relation_tuples
      summary: Write relation tuple
      tags:
        - ReBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - object
                - relation
                - subject
              properties:
                object:
                  type: string
                  description: '"type:id"'
                relation:
                  type: string
                subject:
                  type: string
                  description: '"user:<id>" or "type:id#relation" (userset)'
      responses:
        '201':
          description: Tuple written
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/relation-tuples/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_relation_tuples_ById
      summary: Delete relation tuple
      tags:
        - ReBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/relation-tuples/check:
    post:
      operationId: post_v1_tenants_ByTenantID_relation_tuples_check
      summary: Check relation
      tags:
        - ReBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - object
                - relation
                - user_id
              properties:
                object:
                  type: string
                relation:
                  type: string
                user_id:
                  type: string
      responses:
        '200':
          description: '{ allowed: bool }'
          content:
            application/json:
              schema:
                type: object
                properties:
                  allowed:
                    type: boolean
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/ip-rules:
    get:
      operationId: get_v1_tenants_ByTenantID_ip_rules
      summary: List rules + enforcement
      tags:
        - IP Rules
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post_v1_tenants_ByTenantID_ip_rules
      summary: Add rule
      tags:
        - IP Rules
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/ip-rules/check:
    post:
      operationId: post_v1_tenants_ByTenantID_ip_rules_check
      summary: Check an address
      tags:
        - IP Rules
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/ip-rules/config:
    put:
      operationId: put_v1_tenants_ByTenantID_ip_rules_config
      summary: Set enforcement
      tags:
        - IP Rules
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/ip-rules/{ruleID}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_ip_rules_ByRuleID
      summary: Delete rule
      tags:
        - IP Rules
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: ruleID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/policy:
    get:
      operationId: get_v1_tenants_ByTenantID_policy
      summary: Get policy
      tags:
        - Policy
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put_v1_tenants_ByTenantID_policy
      summary: Update policy
      tags:
        - Policy
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/roles:
    get:
      operationId: get_v1_tenants_ByTenantID_roles
      summary: List roles
      tags:
        - RBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Roles
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Role'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_roles
      summary: Create role
      tags:
        - RBAC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleCreate'
      responses:
        '201':
          description: Role created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Role'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/users/{userID}/tenants/{tenantID}/permissions:
    get:
      operationId: get_v1_users_ByUserID_tenants_ByTenantID_permissions
      summary: Effective permissions
      tags:
        - RBAC
      parameters:
        - name: userID
          in: path
          required: true
          schema:
            type: string
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Effective permissions
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/users/{userID}/tenants/{tenantID}/roles/{roleID}:
    delete:
      operationId: delete_v1_users_ByUserID_tenants_ByTenantID_roles_ByRoleID
      summary: Unassign role from user
      tags:
        - RBAC
      parameters:
        - name: userID
          in: path
          required: true
          schema:
            type: string
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: roleID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Unassigned
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    post:
      operationId: post_v1_users_ByUserID_tenants_ByTenantID_roles_ByRoleID
      summary: Assign role to user
      tags:
        - RBAC
      parameters:
        - name: userID
          in: path
          required: true
          schema:
            type: string
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: roleID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      responses:
        '204':
          description: Assigned
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/groups:
    post:
      operationId: post_v1_groups
      summary: Create group
      tags:
        - Groups
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/groups/{id}:
    delete:
      operationId: delete_v1_groups_ById
      summary: Delete group
      tags:
        - Groups
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/groups/{id}/members:
    get:
      operationId: get_v1_groups_ById_members
      summary: List members
      tags:
        - Groups
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/groups/{id}/members/{userID}:
    delete:
      operationId: delete_v1_groups_ById_members_ByUserID
      summary: Remove member
      tags:
        - Groups
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - name: userID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post_v1_groups_ById_members_ByUserID
      summary: Add member
      tags:
        - Groups
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - name: userID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/invites:
    post:
      operationId: post_v1_invites
      summary: Create invite
      tags:
        - Invites
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/invites/accept:
    post:
      operationId: post_v1_invites_accept
      summary: Accept invite (public)
      tags:
        - Invites
      security: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/invites/{id}:
    delete:
      operationId: delete_v1_invites_ById
      summary: Revoke invite
      tags:
        - Invites
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants:
    get:
      operationId: get_v1_tenants
      summary: List tenants
      tags:
        - Tenants
      parameters:
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Cursor'
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Tenant page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: post_v1_tenants
      summary: Create tenant
      tags:
        - Tenants
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TenantCreate'
      responses:
        '201':
          description: Created; caller becomes owner (token pair included)
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantCreateResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{id}:
    delete:
      operationId: delete_v1_tenants_ById
      summary: Delete tenant
      tags:
        - Tenants
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    get:
      operationId: get_v1_tenants_ById
      summary: Get tenant
      tags:
        - Tenants
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Tenant
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: patch_v1_tenants_ById
      summary: Update tenant
      tags:
        - Tenants
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TenantUpdate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Tenant'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/branding:
    get:
      operationId: get_v1_tenants_ByTenantID_branding
      summary: Get branding
      tags:
        - Branding
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put_v1_tenants_ByTenantID_branding
      summary: Update branding
      tags:
        - Branding
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/groups:
    get:
      operationId: get_v1_tenants_ByTenantID_groups
      summary: List groups
      tags:
        - Groups
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/invites:
    get:
      operationId: get_v1_tenants_ByTenantID_invites
      summary: List invites
      tags:
        - Invites
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/users:
    get:
      operationId: get_v1_users
      summary: List users
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Cursor'
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: User page
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserPage'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: post_v1_users
      summary: Create user
      tags:
        - Users
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreate'
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/users/deleted:
    get:
      operationId: get_v1_users_deleted
      summary: List deleted users
      tags:
        - Users
      parameters:
        - $ref: '#/components/parameters/Limit'
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Soft-deleted users
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/User'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/users/{id}:
    delete:
      operationId: delete_v1_users_ById
      summary: Delete user
      tags:
        - Users
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Soft-deleted
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    get:
      operationId: get_v1_users_ById
      summary: Get user
      tags:
        - Users
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: User
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: patch_v1_users_ById
      summary: Update user
      tags:
        - Users
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/users/{id}/password:
    post:
      operationId: post_v1_users_ById_password
      summary: Set password
      tags:
        - Users
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - password
              properties:
                password:
                  type: string
                  minLength: 8
                  maxLength: 256
      responses:
        '204':
          description: Password set
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/users/{id}/mfa:
    delete:
      operationId: delete_v1_users_ById_mfa
      summary: Admin reset user MFA
      description: Account-recovery for a locked-out user. Requires the `user.write` permission; audited as `mfa.admin_reset`.
      tags:
        - Users
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: MFA reset; returns a confirmation message
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/users/{id}/purge:
    delete:
      operationId: delete_v1_users_ById_purge
      summary: Purge user
      tags:
        - Users
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Permanently purged
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/users/{id}/restore:
    post:
      operationId: post_v1_users_ById_restore
      summary: Restore user
      tags:
        - Users
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      responses:
        '200':
          description: Restored
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/User'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/users/{id}/verify/email/confirm:
    post:
      operationId: post_v1_users_ById_verify_email_confirm
      summary: Confirm email verification
      tags:
        - Verification
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - code
              properties:
                code:
                  type: string
      responses:
        '200':
          description: Email verified; returns a confirmation message
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/users/{id}/verify/email/start:
    post:
      operationId: post_v1_users_ById_verify_email_start
      summary: Start email verification
      description: Sends a 6-digit code to the address on file. Pass `email` only to verify a different address.
      tags:
        - Verification
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  description: Optional; defaults to the user's email on file.
      responses:
        '200':
          description: Code sent; returns a confirmation message
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/users/{id}/verify/phone/confirm:
    post:
      operationId: post_v1_users_ById_verify_phone_confirm
      summary: Confirm phone verification
      tags:
        - Verification
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - code
              properties:
                code:
                  type: string
      responses:
        '200':
          description: Phone verified; returns a confirmation message
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/users/{id}/verify/phone/start:
    post:
      operationId: post_v1_users_ById_verify_phone_start
      summary: Start phone verification
      description: Sends a 6-digit code to the number on file. Pass `phone` only to verify a different number.
      tags:
        - Verification
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                phone:
                  type: string
                  description: Optional; defaults to the user's phone on file.
      responses:
        '200':
          description: Code sent; returns a confirmation message
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/domains:
    get:
      operationId: get_v1_tenants_ByTenantID_domains
      summary: List domains
      tags:
        - Domains
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Domains with their DNS verification records
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_domains
      summary: Claim domain
      tags:
        - Domains
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - domain
              properties:
                domain:
                  type: string
      responses:
        '201':
          description: Domain claimed; publish the returned TXT record then verify
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/domains/{id}/verify:
    post:
      operationId: post_v1_tenants_ByTenantID_domains_ById_verify
      summary: Verify domain
      tags:
        - Domains
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Verification result (verified_at set on success)
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/domains/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_domains_ById
      summary: Remove domain
      tags:
        - Domains
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Domain removed
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /.well-known/jwks.json:
    get:
      operationId: get_wellKnown_jwks_json
      summary: JWKS
      tags:
        - OIDC
      security: []
      responses:
        '200':
          description: JWK Set
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/JWKS'
  /.well-known/openid-configuration:
    get:
      operationId: get_wellKnown_openid_configuration
      summary: OpenID configuration
      tags:
        - OIDC
      security: []
      responses:
        '200':
          description: Discovery metadata
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OIDCDiscovery'
  /.well-known/oauth-protected-resource:
    get:
      operationId: get_wellKnown_oauth_protected_resource
      summary: Protected resource metadata
      description: Protected-resource metadata for MCP authorization-server compliance. Advertises the resource identifier, its authorization server(s), and the supported bearer methods and token-signing algorithms.
      tags:
        - OIDC
      security: []
      responses:
        '200':
          description: Protected-resource metadata
          content:
            application/json:
              schema:
                type: object
                properties:
                  resource:
                    type: string
                  authorization_servers:
                    type: array
                    items:
                      type: string
                  bearer_methods_supported:
                    type: array
                    items:
                      type: string
                  resource_signing_alg_values_supported:
                    type: array
                    items:
                      type: string
                  scopes_provided:
                    type: array
                    items:
                      type: string
                  resource_documentation:
                    type: string
  /ldap/{id}/authenticate:
    post:
      operationId: post_ldap_ById_authenticate
      summary: Authenticate (public)
      tags:
        - LDAP
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /oauth/introspect:
    post:
      operationId: post_oauth_introspect
      summary: Token introspect (RFC 7662)
      tags:
        - OIDC
      security:
        - clientCredentials: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - token
              properties:
                token:
                  type: string
                token_type_hint:
                  type: string
      responses:
        '200':
          description: Introspection result
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Introspection'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /oauth/revoke:
    post:
      operationId: post_oauth_revoke
      summary: Token revoke (RFC 7009)
      tags:
        - OIDC
      security:
        - clientCredentials: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - token
              properties:
                token:
                  type: string
                token_type_hint:
                  type: string
                  enum:
                    - access_token
                    - refresh_token
      responses:
        '200':
          description: 'Revoked (RFC 7009: always 200 even for unknown tokens)'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /saml/acs/{id}:
    post:
      operationId: post_saml_acs_ById
      summary: '[acs] Assertion Consumer Service'
      tags:
        - SAML
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                SAMLResponse:
                  type: string
                RelayState:
                  type: string
      responses:
        '302':
          description: Signature-validated; redirect with a one-time login code
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /saml/exchange:
    post:
      operationId: post_saml_exchange
      summary: Exchange code (public)
      tags:
        - SAML
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - code
              properties:
                code:
                  type: string
      responses:
        '200':
          description: Token pair
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TokenPair'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /saml/idp/metadata:
    get:
      operationId: get_saml_idp_metadata
      summary: '[idp] IdP metadata'
      tags:
        - SAML
      security: []
      responses:
        '200':
          description: IdP metadata XML
          content:
            application/xml:
              schema:
                type: string
  /saml/idp/sso:
    get:
      operationId: get_saml_idp_sso
      summary: '[idp] IdP SSO (redirect binding)'
      tags:
        - SAML
      parameters:
        - in: query
          name: SAMLRequest
          schema:
            type: string
        - in: query
          name: RelayState
          schema:
            type: string
      security: []
      responses:
        '200':
          description: Auto-submit POST form back to the SP ACS with a signed SAMLResponse
          content:
            text/html:
              schema:
                type: string
        '302':
          description: Redirect to hosted login when no SSO session
        '400':
          $ref: '#/components/responses/BadRequest'
    post:
      operationId: post_saml_idp_sso
      summary: '[idp] IdP SSO (POST binding)'
      tags:
        - SAML
      security: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              properties:
                SAMLRequest:
                  type: string
                RelayState:
                  type: string
      responses:
        '200':
          description: Auto-submit POST form back to the SP ACS with a signed SAMLResponse
          content:
            text/html:
              schema:
                type: string
        '302':
          description: Redirect to hosted login when no SSO session
        '400':
          $ref: '#/components/responses/BadRequest'
  /saml/login/{id}:
    get:
      operationId: get_saml_login_ById
      summary: Login redirect (public)
      tags:
        - SAML
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security: []
      responses:
        '302':
          description: Redirect to the external IdP with an AuthnRequest
        '404':
          $ref: '#/components/responses/NotFound'
  /saml/metadata/{id}:
    get:
      operationId: get_saml_metadata_ById
      summary: SP metadata (public)
      tags:
        - SAML
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security: []
      responses:
        '200':
          description: SP metadata XML
          content:
            application/xml:
              schema:
                type: string
        '404':
          $ref: '#/components/responses/NotFound'
  /scim/v2/Groups:
    get:
      operationId: get_scim_v2_Groups
      summary: '[scim] List groups'
      tags:
        - SCIM
      parameters:
        - in: query
          name: filter
          schema:
            type: string
        - in: query
          name: startIndex
          schema:
            type: integer
        - in: query
          name: count
          schema:
            type: integer
      security:
        - scimBearer: []
      responses:
        '200':
          description: ListResponse
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMListResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: post_scim_v2_Groups
      summary: '[scim] Create group'
      tags:
        - SCIM
      security:
        - scimBearer: []
      requestBody:
        required: true
        content:
          application/scim+json:
            schema:
              $ref: '#/components/schemas/SCIMGroup'
      responses:
        '201':
          description: Group created
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMGroup'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'
  /scim/v2/Groups/{id}:
    delete:
      operationId: delete_scim_v2_Groups_ById
      summary: '[scim] Delete group'
      tags:
        - SCIM
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - scimBearer: []
      responses:
        '204':
          description: Deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    get:
      operationId: get_scim_v2_Groups_ById
      summary: '[scim] Get group'
      tags:
        - SCIM
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - scimBearer: []
      responses:
        '200':
          description: Group
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMGroup'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: patch_scim_v2_Groups_ById
      summary: '[scim] Patch group'
      tags:
        - SCIM
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - scimBearer: []
      requestBody:
        required: true
        content:
          application/scim+json:
            schema:
              $ref: '#/components/schemas/SCIMPatchOp'
      responses:
        '200':
          description: Patched
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMGroup'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    put:
      operationId: put_scim_v2_Groups_ById
      summary: '[scim] Replace group'
      tags:
        - SCIM
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - scimBearer: []
      requestBody:
        required: true
        content:
          application/scim+json:
            schema:
              $ref: '#/components/schemas/SCIMGroup'
      responses:
        '200':
          description: Replaced
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMGroup'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /scim/v2/ResourceTypes:
    get:
      operationId: get_scim_v2_ResourceTypes
      summary: '[scim] ResourceTypes'
      tags:
        - SCIM
      security:
        - scimBearer: []
      responses:
        '200':
          description: SCIM metadata
          content:
            application/scim+json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
  /scim/v2/Schemas:
    get:
      operationId: get_scim_v2_Schemas
      summary: '[scim] Schemas'
      tags:
        - SCIM
      security:
        - scimBearer: []
      responses:
        '200':
          description: SCIM metadata
          content:
            application/scim+json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
  /scim/v2/ServiceProviderConfig:
    get:
      operationId: get_scim_v2_ServiceProviderConfig
      summary: '[scim] ServiceProviderConfig'
      tags:
        - SCIM
      security:
        - scimBearer: []
      responses:
        '200':
          description: SCIM metadata
          content:
            application/scim+json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
  /scim/v2/Users:
    get:
      operationId: get_scim_v2_Users
      summary: '[scim] List users'
      tags:
        - SCIM
      parameters:
        - in: query
          name: filter
          schema:
            type: string
          description: SCIM filter, e.g. userName eq "a@b.com"
        - in: query
          name: startIndex
          schema:
            type: integer
            minimum: 1
        - in: query
          name: count
          schema:
            type: integer
            minimum: 0
      security:
        - scimBearer: []
      responses:
        '200':
          description: ListResponse
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMListResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: post_scim_v2_Users
      summary: '[scim] Create user'
      tags:
        - SCIM
      security:
        - scimBearer: []
      requestBody:
        required: true
        content:
          application/scim+json:
            schema:
              $ref: '#/components/schemas/SCIMUser'
          application/json:
            schema:
              $ref: '#/components/schemas/SCIMUser'
      responses:
        '201':
          description: User provisioned
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMUser'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '409':
          $ref: '#/components/responses/Conflict'
  /scim/v2/Users/{id}:
    delete:
      operationId: delete_scim_v2_Users_ById
      summary: '[scim] Delete user'
      tags:
        - SCIM
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - scimBearer: []
      responses:
        '204':
          description: Deprovisioned
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    get:
      operationId: get_scim_v2_Users_ById
      summary: '[scim] Get user'
      tags:
        - SCIM
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - scimBearer: []
      responses:
        '200':
          description: User
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMUser'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: patch_scim_v2_Users_ById
      summary: '[scim] Patch user (deprovision)'
      tags:
        - SCIM
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - scimBearer: []
      requestBody:
        required: true
        content:
          application/scim+json:
            schema:
              $ref: '#/components/schemas/SCIMPatchOp'
      responses:
        '200':
          description: Patched
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMUser'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    put:
      operationId: put_scim_v2_Users_ById
      summary: '[scim] Replace user'
      tags:
        - SCIM
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - scimBearer: []
      requestBody:
        required: true
        content:
          application/scim+json:
            schema:
              $ref: '#/components/schemas/SCIMUser'
      responses:
        '200':
          description: Replaced
          content:
            application/scim+json:
              schema:
                $ref: '#/components/schemas/SCIMUser'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/oauth/authorize:
    get:
      operationId: get_v1_oauth_authorize
      summary: Authorize
      tags:
        - OIDC
      parameters:
        - in: query
          name: client_id
          required: true
          schema:
            type: string
        - in: query
          name: redirect_uri
          required: true
          schema:
            type: string
            format: uri
        - in: query
          name: response_type
          required: true
          schema:
            type: string
            enum:
              - code
        - in: query
          name: scope
          schema:
            type: string
        - in: query
          name: state
          schema:
            type: string
        - in: query
          name: code_challenge
          schema:
            type: string
        - in: query
          name: code_challenge_method
          schema:
            type: string
            enum:
              - S256
        - in: query
          name: nonce
          schema:
            type: string
      security:
        - ssoCookie: []
      responses:
        '302':
          description: Redirect to the hosted-login UI or back to the client with a code
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/oauth/authorize/decision:
    post:
      operationId: post_v1_oauth_authorize_decision
      summary: Authorize decision (consent)
      tags:
        - OIDC
      security:
        - ssoCookie: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - request_id
                - decision
              properties:
                request_id:
                  type: string
                decision:
                  type: string
                  enum:
                    - allow
                    - deny
      responses:
        '302':
          description: Redirect back to the client with code or error
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/oauth/device:
    get:
      operationId: get_v1_oauth_device
      summary: Device verification context
      description: Returns the requesting client's display name and requested scopes for a pending device-authorization, looked up by user_code, so the hosted-login /device page can render the approval screen. SSO-cookie gated.
      tags:
        - OIDC
      parameters:
        - in: query
          name: user_code
          required: true
          schema:
            type: string
          description: The human-typed user_code (e.g. BCDF-GHJK).
      security:
        - ssoCookie: []
      responses:
        '200':
          description: Device verification context
          content:
            application/json:
              schema:
                type: object
                properties:
                  client_name:
                    type: string
                  scopes:
                    type: array
                    items:
                      type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/oauth/device/decision:
    post:
      operationId: post_v1_oauth_device_decision
      summary: Device decision (approve)
      description: The SSO-cookie-identified user approves or denies a pending device request identified by user_code. On approval the user (who must belong to the client's tenant) is bound and the device can complete its token poll.
      tags:
        - OIDC
      security:
        - ssoCookie: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - user_code
                - approve
              properties:
                user_code:
                  type: string
                approve:
                  type: boolean
      responses:
        '200':
          description: Decision recorded
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    enum:
                      - authorized
                      - denied
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
  /v1/oauth/device_authorization:
    post:
      operationId: post_v1_oauth_device_authorization
      summary: Device authorization
      description: Client-authenticated endpoint for input-constrained (CLI/TV/IoT) clients. Returns a (device_code, user_code) pair plus the verification URIs; the device then polls /v1/oauth/token-code with grant_type=urn:ietf:params:oauth:grant-type:device_code.
      tags:
        - OIDC
      security:
        - clientCredentials: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - client_id
              properties:
                client_id:
                  type: string
                client_secret:
                  type: string
                scope:
                  type: string
      responses:
        '200':
          description: Device authorization response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeviceAuthorizationResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/oauth/login-context:
    get:
      operationId: get_v1_oauth_login_context
      summary: Login context
      tags:
        - OIDC
      parameters:
        - in: query
          name: request_id
          required: true
          schema:
            type: string
      security:
        - ssoCookie: []
      responses:
        '200':
          description: Hosted-login context (client name, scopes, branding)
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/oauth/logout:
    get:
      operationId: get_v1_oauth_logout
      summary: RP-initiated logout
      tags:
        - OIDC
      parameters:
        - in: query
          name: id_token_hint
          schema:
            type: string
        - in: query
          name: post_logout_redirect_uri
          schema:
            type: string
            format: uri
        - in: query
          name: state
          schema:
            type: string
      security:
        - ssoCookie: []
      responses:
        '302':
          description: Redirect to post_logout_redirect_uri
        '400':
          $ref: '#/components/responses/BadRequest'
    post:
      operationId: post_v1_oauth_logout
      summary: RP-initiated logout
      tags:
        - OIDC
      parameters:
        - in: query
          name: id_token_hint
          schema:
            type: string
        - in: query
          name: post_logout_redirect_uri
          schema:
            type: string
            format: uri
        - in: query
          name: state
          schema:
            type: string
      security:
        - ssoCookie: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      responses:
        '302':
          description: Redirect to post_logout_redirect_uri
        '400':
          $ref: '#/components/responses/BadRequest'
  /v1/oauth/token:
    post:
      operationId: post_v1_oauth_token
      summary: OAuth token (client_credentials)
      tags:
        - OIDC
      security:
        - clientCredentials: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              type: object
              required:
                - grant_type
              properties:
                grant_type:
                  type: string
                  enum:
                    - client_credentials
                client_id:
                  type: string
                client_secret:
                  type: string
                scope:
                  type: string
      responses:
        '200':
          description: Token response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthTokenResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/oauth/token-code:
    post:
      operationId: post_v1_oauth_token_code
      summary: Token (authorization_code)
      tags:
        - OIDC
      security:
        - clientCredentials: []
      requestBody:
        required: true
        content:
          application/x-www-form-urlencoded:
            schema:
              $ref: '#/components/schemas/OAuthTokenRequest'
      responses:
        '200':
          description: Token response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OAuthTokenResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/oauth/userinfo:
    get:
      operationId: get_v1_oauth_userinfo
      summary: UserInfo
      tags:
        - OIDC
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: UserInfo claims
          content:
            application/json:
              schema:
                type: object
                properties:
                  sub:
                    type: string
                    format: uuid
                  tenant_id:
                    type: string
                    format: uuid
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/oidc/clients:
    post:
      operationId: post_v1_oidc_clients
      summary: Register OIDC client
      tags:
        - OIDC
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OIDCClientCreate'
      responses:
        '201':
          description: Client created (secret shown once)
          content:
            application/json:
              schema:
                type: object
                properties:
                  client:
                    $ref: '#/components/schemas/OIDCClient'
                  client_secret:
                    type: string
                  warning:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/oidc/clients/{id}:
    delete:
      operationId: delete_v1_oidc_clients_ById
      summary: Delete OIDC client (by scope)
      tags:
        - OIDC
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Client deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/oidc/signing-keys:
    get:
      operationId: get_v1_oidc_signing_keys
      summary: Signing keys metadata
      tags:
        - OIDC
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Signing keys (active + retired)
          content:
            application/json:
              schema:
                type: object
                properties:
                  keys:
                    type: array
                    items:
                      $ref: '#/components/schemas/SigningKey'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/oidc/signing-keys/rotate:
    post:
      operationId: post_v1_oidc_signing_keys_rotate
      summary: Rotate signing key
      description: Generates a fresh EC P-256 signing key, makes it active, and retires the previous key to verify-only. The new private key PEM is returned once in the response — the operator must persist it as JWT_SIGNING_KEY before the next restart. Existing tokens remain verifiable during the grace window.
      tags:
        - OIDC
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Rotation complete (new private key shown once)
          content:
            application/json:
              schema:
                type: object
                properties:
                  kid:
                    type: string
                  alg:
                    type: string
                  private_key_pem:
                    type: string
                  warning:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/service-principals:
    post:
      operationId: post_v1_service_principals
      summary: Create service principal
      tags:
        - OIDC
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ServicePrincipalCreate'
      responses:
        '201':
          description: Service principal created (secret shown once)
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/service-principals/{id}:
    delete:
      operationId: delete_v1_service_principals_ById
      summary: Disable service principal
      tags:
        - OIDC
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/social/exchange:
    post:
      operationId: post_v1_social_exchange
      summary: Exchange social code
      tags:
        - Social
      security: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/social/identities/{id}:
    delete:
      operationId: delete_v1_social_identities_ById
      summary: Unlink identity
      tags:
        - Social
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/social/providers:
    post:
      operationId: post_v1_social_providers
      summary: Upsert provider
      tags:
        - Social
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/social/{provider}/callback:
    get:
      operationId: get_v1_social_ByProvIDer_callback
      summary: Social login callback
      tags:
        - Social
      parameters:
        - name: provider
          in: path
          required: true
          schema:
            type: string
      security: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/social/{provider}/start:
    get:
      operationId: get_v1_social_ByProvIDer_start
      summary: Start social login
      tags:
        - Social
      parameters:
        - name: provider
          in: path
          required: true
          schema:
            type: string
      security: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/ldap:
    get:
      operationId: get_v1_tenants_ByTenantID_ldap
      summary: List connections
      tags:
        - LDAP
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post_v1_tenants_ByTenantID_ldap
      summary: Create connection
      tags:
        - LDAP
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/ldap/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_ldap_ById
      summary: Delete connection
      tags:
        - LDAP
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get_v1_tenants_ByTenantID_ldap_ById
      summary: Get connection
      tags:
        - LDAP
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    patch:
      operationId: patch_v1_tenants_ByTenantID_ldap_ById
      summary: Update connection
      tags:
        - LDAP
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/ldap/{id}/test:
    post:
      operationId: post_v1_tenants_ByTenantID_ldap_ById_test
      summary: Test bind
      tags:
        - LDAP
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/oauth/devices:
    get:
      operationId: get_v1_tenants_ByTenantID_oauth_devices
      summary: List device authorizations
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Device authorizations
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/OAuthDeviceAuthorization'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/oauth/devices/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_oauth_devices_ById
      summary: Revoke device authorization
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Device authorization revoked
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/oidc/clients:
    get:
      operationId: get_v1_tenants_ByTenantID_oidc_clients
      summary: List OIDC clients
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: OIDC clients
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/OIDCClient'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    post:
      operationId: post_v1_tenants_ByTenantID_oidc_clients
      summary: Create OIDC client
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OIDCClientCreate'
      responses:
        '201':
          description: Client created (secret shown once)
          content:
            application/json:
              schema:
                type: object
                properties:
                  client:
                    $ref: '#/components/schemas/OIDCClient'
                  client_secret:
                    type: string
                  warning:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/oidc/clients/{id}:
    get:
      operationId: get_v1_tenants_ByTenantID_oidc_clients_ById
      summary: Get OIDC client
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: OIDC client
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OIDCClient'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: patch_v1_tenants_ByTenantID_oidc_clients_ById
      summary: Update OIDC client
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/OIDCClientUpdate'
      responses:
        '200':
          description: Updated OIDC client
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OIDCClient'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
    delete:
      operationId: delete_v1_tenants_ByTenantID_oidc_clients_ById
      summary: Delete OIDC client
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Client deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/oidc/clients/{id}/rotate-secret:
    post:
      operationId: post_v1_tenants_ByTenantID_oidc_clients_ById_rotate_secret
      summary: Rotate client secret
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
            format: uuid
        - name: id
          in: path
          required: true
          schema:
            type: string
            format: uuid
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: New client secret (shown once)
          content:
            application/json:
              schema:
                type: object
                properties:
                  client_secret:
                    type: string
                  warning:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/oauth/grants:
    get:
      operationId: get_v1_tenants_ByTenantID_oauth_grants
      summary: List active grants
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Consent grants
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/oauth/grants/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_oauth_grants_ById
      summary: Revoke grant
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Grant revoked
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/saml:
    get:
      operationId: get_v1_tenants_ByTenantID_saml
      summary: List connections
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Connections
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/SAMLConnection'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_saml
      summary: Create connection
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SAMLConnectionCreate'
      responses:
        '201':
          description: Connection created
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SAMLConnection'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/saml-providers:
    get:
      operationId: get_v1_tenants_ByTenantID_saml_providers
      summary: List SAML SPs (IdP side)
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Service providers
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/SAMLServiceProvider'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_saml_providers
      summary: Register SAML SP (IdP side)
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SAMLServiceProviderCreate'
      responses:
        '201':
          description: SP registered
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SAMLServiceProvider'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/saml-providers/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_saml_providers_ById
      summary: Delete SAML SP
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    get:
      operationId: get_v1_tenants_ByTenantID_saml_providers_ById
      summary: Get SAML SP
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Service provider
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SAMLServiceProvider'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: patch_v1_tenants_ByTenantID_saml_providers_ById
      summary: Update SAML SP
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SAMLServiceProviderCreate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SAMLServiceProvider'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/saml/{id}/test:
    post:
      operationId: post_v1_tenants_ByTenantID_saml_ById_test
      summary: Test SAML connection
      description: Runs offline checks (entity ID present, https SSO URL, the signing certificate parses and is in its validity window, email attribute mapped) and returns per-check results. No network I/O.
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Per-check preflight results
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/saml/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_saml_ById
      summary: Delete connection
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    get:
      operationId: get_v1_tenants_ByTenantID_saml_ById
      summary: Get connection
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Connection
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SAMLConnection'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: patch_v1_tenants_ByTenantID_saml_ById
      summary: Update connection
      tags:
        - SAML
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SAMLConnectionCreate'
      responses:
        '200':
          description: Updated
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SAMLConnection'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/scim:
    get:
      operationId: get_v1_tenants_ByTenantID_scim
      summary: Get SCIM config
      tags:
        - SCIM
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/scim/token:
    delete:
      operationId: delete_v1_tenants_ByTenantID_scim_token
      summary: Revoke SCIM token
      tags:
        - SCIM
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post_v1_tenants_ByTenantID_scim_token
      summary: Rotate SCIM token
      tags:
        - SCIM
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/scim/users:
    get:
      operationId: get_v1_tenants_ByTenantID_scim_users
      summary: List provisioned users
      tags:
        - SCIM
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/service-principals:
    get:
      operationId: get_v1_tenants_ByTenantID_service_principals
      summary: List service principals
      tags:
        - OIDC
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/social/providers:
    get:
      operationId: get_v1_tenants_ByTenantID_social_providers
      summary: List providers
      tags:
        - Social
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/users/{userID}/social/identities:
    get:
      operationId: get_v1_users_ByUserID_social_identities
      summary: List linked identities
      tags:
        - Social
      parameters:
        - name: userID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/api-keys:
    post:
      operationId: post_v1_api_keys
      summary: Create API key
      tags:
        - API Keys
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiKeyCreate'
      responses:
        '201':
          description: Created; secret shown once
          content:
            application/json:
              schema:
                type: object
                properties:
                  api_key:
                    $ref: '#/components/schemas/ApiKey'
                  secret:
                    type: string
                  warning:
                    type: string
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/api-keys/{id}:
    delete:
      operationId: delete_v1_api_keys_ById
      summary: Revoke API key
      tags:
        - API Keys
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Revoked
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/api-keys:
    get:
      operationId: get_v1_tenants_ByTenantID_api_keys
      summary: List API keys
      tags:
        - API Keys
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: API keys
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/ApiKey'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/credentials/verify:
    post:
      operationId: post_v1_credentials_verify
      summary: Verify credential (public)
      description: Any relying party can present a JWT-serialized W3C Verifiable Credential issued by this server; the response reports validity (signature, issuer, expiry, and revocation status) plus the credential subject + claims. No session required.
      tags:
        - Credentials
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - credential
              properties:
                credential:
                  type: string
                  description: The JWT-VC string.
      responses:
        '200':
          description: '{ valid, subject, issuer, vc, ... }'
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/credentials:
    get:
      operationId: get_v1_tenants_ByTenantID_credentials
      summary: List credentials
      tags:
        - Credentials
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Issued credentials (registry view)
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_credentials
      summary: Issue credential
      tags:
        - Credentials
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - subject
                - type
              properties:
                subject:
                  type: string
                type:
                  type: string
                claims:
                  type: object
                  additionalProperties: true
                ttl_seconds:
                  type: integer
      responses:
        '201':
          description: Signed JWT-VC + credential id
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/credentials/{id}/revoke:
    post:
      operationId: post_v1_tenants_ByTenantID_credentials_ById_revoke
      summary: Revoke credential
      tags:
        - Credentials
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Revoked
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/agents/token:
    post:
      operationId: post_v1_agents_token
      summary: Mint agent token
      description: An AI agent authenticates with its agent_id + secret (JSON body or HTTP Basic) and receives an ephemeral access token marked actor_type="agent" (+ agent_id claim), verifiable on the standard JWKS path. No user session.
      tags:
        - Agents
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - agent_id
                - secret
              properties:
                agent_id:
                  type: string
                secret:
                  type: string
      responses:
        '200':
          description: Short-lived agent access token
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/tenants/{tenantID}/agents:
    get:
      operationId: get_v1_tenants_ByTenantID_agents
      summary: List agents
      tags:
        - Agents
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Agents (secrets are write-only, not returned)
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_agents
      summary: Create agent
      tags:
        - Agents
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                name:
                  type: string
                scopes:
                  type: array
                  items:
                    type: string
                token_ttl_seconds:
                  type: integer
      responses:
        '201':
          description: Agent created (secret returned once)
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/agents/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_agents_ById
      summary: Delete agent
      tags:
        - Agents
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: patch_v1_tenants_ByTenantID_agents_ById
      summary: Update agent
      description: Sets or clears the agent's disabled_at. A disabled agent can no longer mint tokens; existing tokens remain valid until they expire.
      tags:
        - Agents
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - disabled
              properties:
                disabled:
                  type: boolean
      responses:
        '204':
          description: Updated
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/agents/{id}/suspend:
    post:
      operationId: post_v1_tenants_ByTenantID_agents_ById_suspend
      summary: Suspend agent
      tags:
        - Agents
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Suspended
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/agents/kill-all:
    post:
      operationId: post_v1_tenants_ByTenantID_agents_kill_all
      summary: Suspend all agents
      description: Security incident-response control. Sets disabled_at on all of the tenant's agents in a single transaction. Returns the number suspended.
      tags:
        - Agents
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Agents suspended
          content:
            application/json:
              schema:
                type: object
                properties:
                  suspended:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/tenants/{tenantID}/auth-hooks:
    get:
      operationId: get_v1_tenants_ByTenantID_auth_hooks
      summary: List auth hooks
      tags:
        - Auth Hooks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Configured hooks (secrets are write-only, not returned)
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_auth_hooks
      summary: Create auth hook
      tags:
        - Auth Hooks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - url
              properties:
                url:
                  type: string
                  format: uri
                secret:
                  type: string
                fail_open:
                  type: boolean
      responses:
        '201':
          description: Hook created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/auth-hooks/{id}:
    patch:
      operationId: patch_v1_tenants_ByTenantID_auth_hooks_ById
      summary: Update auth hook
      tags:
        - Auth Hooks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                enabled:
                  type: boolean
                fail_open:
                  type: boolean
      responses:
        '200':
          description: Updated
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: delete_v1_tenants_ByTenantID_auth_hooks_ById
      summary: Delete auth hook
      tags:
        - Auth Hooks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Removed
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/vault/{name}:
    get:
      operationId: get_v1_vault_ByName
      summary: Vault read by name
      description: Returns a secret's value to a caller holding a "vault:<name>" (or "vault:read") scope — e.g. an AI agent fetching a credential at runtime without embedding it. Tenant comes from the caller's token; every access is audited.
      tags:
        - Secrets
      parameters:
        - name: name
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: '{ name, value }'
          content:
            application/json:
              schema:
                type: object
                properties:
                  name:
                    type: string
                  value:
                    type: string
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/secrets:
    get:
      operationId: get_v1_tenants_ByTenantID_secrets
      summary: List secrets
      tags:
        - Secrets
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    post:
      operationId: post_v1_tenants_ByTenantID_secrets
      summary: Create secret
      tags:
        - Secrets
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/secrets/{id}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_secrets_ById
      summary: Delete secret
      tags:
        - Secrets
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    patch:
      operationId: patch_v1_tenants_ByTenantID_secrets_ById
      summary: Rotate secret
      tags:
        - Secrets
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/secrets/{id}/reveal:
    post:
      operationId: post_v1_tenants_ByTenantID_secrets_ById_reveal
      summary: Reveal secret
      tags:
        - Secrets
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/webhooks:
    get:
      operationId: get_v1_tenants_ByTenantID_webhooks
      summary: List webhooks
      tags:
        - Webhooks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/webhooks:
    post:
      operationId: post_v1_webhooks
      summary: Create webhook
      tags:
        - Webhooks
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/webhooks/{id}:
    get:
      operationId: get_v1_webhooks_ById
      summary: Get webhook
      tags:
        - Webhooks
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Webhook subscription
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: delete_v1_webhooks_ById
      summary: Disable webhook
      tags:
        - Webhooks
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/webhooks/{id}/deliveries:
    get:
      operationId: get_v1_webhooks_ById_deliveries
      summary: List deliveries
      tags:
        - Webhooks
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Recent deliveries
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /v1/webhooks/{id}/deliveries/{deliveryID}/retry:
    post:
      operationId: post_v1_webhooks_ById_deliveries_ByDeliveryID_retry
      summary: Retry delivery
      tags:
        - Webhooks
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
        - name: deliveryID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Delivery re-queued
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/webhooks/{id}/test:
    post:
      operationId: post_v1_webhooks_ById_test
      summary: Test webhook
      tags:
        - Webhooks
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/rate-limits:
    get:
      operationId: get_v1_tenants_ByTenantID_rate_limits
      summary: Get rate limits
      description: Returns the effective per-bucket limits (tenant, user, api_key) — the platform defaults merged with any tenant-specific overrides.
      tags:
        - Rate Limits
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Effective limits
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantRateLimits'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    put:
      operationId: put_v1_tenants_ByTenantID_rate_limits
      summary: Set rate limits
      tags:
        - Rate Limits
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TenantRateLimits'
      responses:
        '200':
          description: Updated effective limits
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TenantRateLimits'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
    delete:
      operationId: delete_v1_tenants_ByTenantID_rate_limits
      summary: Reset rate limits
      tags:
        - Rate Limits
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Overrides cleared
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
  /healthz:
    get:
      operationId: get_healthz
      summary: Liveness
      tags:
        - Health
      security: []
      responses:
        '200':
          description: Alive
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
                    example: ok
  /metrics:
    get:
      operationId: get_metrics
      summary: Metrics (Prometheus)
      tags:
        - Health
      security: []
      responses:
        '200':
          description: Prometheus exposition format
          content:
            text/plain:
              schema:
                type: string
  /readyz:
    get:
      operationId: get_readyz
      summary: Readiness
      tags:
        - Health
      security: []
      responses:
        '200':
          description: Ready
          content:
            application/json:
              schema:
                type: object
                properties:
                  status:
                    type: string
        '503':
          description: Not ready (a dependency is down)
  /v1/admin/outbox/dlq:
    get:
      operationId: get_v1_admin_outbox_dlq
      summary: List DLQ events
      tags:
        - Admin
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/billing/checkout:
    post:
      operationId: post_v1_tenants_ByTenantID_billing_checkout
      summary: Start checkout
      description: 'Returns a hosted-payment URL to redirect the admin to, or {status:"active"} when the plan is free or no card provider serves the currency (direct activation). Provider routing: INR → Razorpay, else → Stripe. The provider''s webhook later activates the subscription.'
      tags:
        - Billing
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - plan_code
                - currency
                - success_url
                - cancel_url
              properties:
                plan_code:
                  type: string
                currency:
                  type: string
                success_url:
                  type: string
                  format: uri
                cancel_url:
                  type: string
                  format: uri
      responses:
        '200':
          description: Either a checkout URL ({status:"checkout"}) or {status:"active"}
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/billing/webhooks/{provider}:
    post:
      operationId: post_v1_billing_webhooks_ByProvider
      summary: Payment webhook
      description: Receives provider payment events. Authenticated by the provider's webhook signature (no user session); on a verified successful payment the referenced checkout is completed idempotently.
      tags:
        - Billing
      security: []
      parameters:
        - name: provider
          in: path
          required: true
          schema:
            type: string
            enum:
              - stripe
              - razorpay
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
      responses:
        '200':
          description: Event acknowledged
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/billing/plans:
    get:
      operationId: get_v1_billing_plans
      summary: List plans
      tags:
        - Billing
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/gdpr/purge:
    post:
      operationId: post_v1_gdpr_purge
      summary: Create purge request
      tags:
        - GDPR
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/gdpr/purge/{id}:
    delete:
      operationId: delete_v1_gdpr_purge_ById
      summary: Cancel purge request
      tags:
        - GDPR
      parameters:
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/analytics/overview:
    get:
      operationId: get_v1_tenants_ByTenantID_analytics_overview
      summary: Tenant analytics overview
      tags:
        - Analytics
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/audit:
    get:
      operationId: get_v1_tenants_ByTenantID_audit
      summary: List audit events
      tags:
        - Audit
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/audit/verify:
    get:
      operationId: get_v1_tenants_ByTenantID_audit_verify
      summary: Verify audit chain
      tags:
        - Audit
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/billing/invoices:
    get:
      operationId: get_v1_tenants_ByTenantID_billing_invoices
      summary: List invoices
      tags:
        - Billing
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/billing/subscription:
    get:
      operationId: get_v1_tenants_ByTenantID_billing_subscription
      summary: Get subscription
      tags:
        - Billing
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put_v1_tenants_ByTenantID_billing_subscription
      summary: Subscribe / change plan
      tags:
        - Billing
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/billing/subscription/cancel:
    post:
      operationId: post_v1_tenants_ByTenantID_billing_subscription_cancel
      summary: Cancel at period end
      tags:
        - Billing
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/email-templates:
    get:
      operationId: get_v1_tenants_ByTenantID_email_templates
      summary: List templates
      tags:
        - Email Templates
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/email-templates/{key}:
    delete:
      operationId: delete_v1_tenants_ByTenantID_email_templates_ByKey
      summary: Reset to default
      tags:
        - Email Templates
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: key
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '204':
          description: No Content
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    get:
      operationId: get_v1_tenants_ByTenantID_email_templates_ByKey
      summary: Get template
      tags:
        - Email Templates
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: key
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put_v1_tenants_ByTenantID_email_templates_ByKey
      summary: Override template
      tags:
        - Email Templates
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: key
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/email-templates/{key}/preview:
    post:
      operationId: post_v1_tenants_ByTenantID_email_templates_ByKey_preview
      summary: Preview template
      tags:
        - Email Templates
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: key
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/gdpr/purge:
    get:
      operationId: get_v1_tenants_ByTenantID_gdpr_purge
      summary: List purge requests
      tags:
        - GDPR
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/log-sinks:
    get:
      operationId: get_v1_tenants_ByTenantID_log_sinks
      summary: List log sinks
      tags:
        - Log Sinks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Configured sinks (tokens are write-only, not returned)
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
    post:
      operationId: post_v1_tenants_ByTenantID_log_sinks
      summary: Create log sink
      tags:
        - Log Sinks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - type
                - endpoint
              properties:
                type:
                  type: string
                  enum:
                    - splunk_hec
                    - datadog
                    - http
                endpoint:
                  type: string
                  format: uri
                token:
                  type: string
      responses:
        '201':
          description: Sink created (streams new audit events from now)
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '422':
          $ref: '#/components/responses/Unprocessable'
  /v1/tenants/{tenantID}/log-sinks/{id}:
    patch:
      operationId: patch_v1_tenants_ByTenantID_log_sinks_ById
      summary: Enable/disable sink
      tags:
        - Log Sinks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                enabled:
                  type: boolean
      responses:
        '200':
          description: Updated
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: delete_v1_tenants_ByTenantID_log_sinks_ById
      summary: Delete sink
      tags:
        - Log Sinks
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
        - name: id
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: Removed
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
  /v1/tenants/{tenantID}/retention:
    get:
      operationId: get_v1_tenants_ByTenantID_retention
      summary: Get retention policy
      tags:
        - Data Retention
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
    put:
      operationId: put_v1_tenants_ByTenantID_retention
      summary: Update retention policy
      tags:
        - Data Retention
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/retention/preview:
    post:
      operationId: post_v1_tenants_ByTenantID_retention_preview
      summary: Preview ripe users
      tags:
        - Data Retention
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/tenants/{tenantID}/retention/run:
    post:
      operationId: post_v1_tenants_ByTenantID_retention_run
      summary: Run purge now
      tags:
        - Data Retention
      parameters:
        - name: tenantID
          in: path
          required: true
          schema:
            type: string
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
        description: Request body summarized; see the handler for exact fields.
      description: Response body summarized; accurate path/method/params/security. Enrich the body later.
      responses:
        '201':
          description: Created
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        '401':
          $ref: '#/components/responses/Unauthorized'
        '403':
          $ref: '#/components/responses/Forbidden'
        '404':
          $ref: '#/components/responses/NotFound'
        '422':
          $ref: '#/components/responses/Unprocessable'
        '429':
          $ref: '#/components/responses/TooManyRequests'
  /v1/notifications:
    get:
      operationId: get_v1_notifications
      summary: List notifications
      tags:
        - Notifications
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '200':
          description: Notification inbox
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                  unread_count:
                    type: integer
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/notifications/mark-all-read:
    post:
      operationId: post_v1_notifications_mark_all_read
      summary: Mark all read
      tags:
        - Notifications
      security:
        - bearerAuth: []
        - apiKeyAuth: []
      responses:
        '204':
          description: All notifications marked read
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'User or service JWT: `Authorization: Bearer <token>`.'
    apiKeyAuth:
      type: apiKey
      in: header
      name: Authorization
      description: 'API key credential. Send `Authorization: ApiKey <key>` (note the `ApiKey ` prefix). Accepted on the same authenticated routes as bearerAuth.'
    scimBearer:
      type: http
      scheme: bearer
      description: 'Per-tenant SCIM provisioning token presented by the IdP: `Authorization: Bearer <scim-token>`. Distinct from user JWTs; rotated via the SCIM admin endpoints.'
    clientCredentials:
      type: oauth2
      description: OAuth 2.0 client credentials. Clients authenticate at the token endpoint via form params (`client_id`/`client_secret`) or HTTP Basic. Revocation/introspection use the same client auth.
      flows:
        clientCredentials:
          tokenUrl: /v1/oauth/token
          scopes: {}
    ssoCookie:
      type: apiKey
      in: cookie
      name: qe_ls
      description: Hosted-login SSO session cookie (HttpOnly). Set by POST /v1/auth/session and consumed by the OAuth authorize/consent flow.
  responses:
    BadRequest:
      description: Malformed request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid credentials
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Forbidden:
      description: Authenticated but not permitted
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    NotFound:
      description: Resource not found
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Conflict:
      description: Resource conflict
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unprocessable:
      description: Validation failed
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    TooManyRequests:
      description: Rate limit exceeded
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Error:
      type: object
      required:
        - error
      description: Canonical error envelope (internal/platform/httpx.WriteError).
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Stable machine code
              example: unauthorized
            message:
              type: string
              example: authentication required
            detail:
              type: string
              description: Optional human detail
            request_id:
              type: string
              description: Correlates with the X-Request-Id header
    TokenPair:
      type: object
      properties:
        access_token:
          type: string
        token_type:
          type: string
          example: Bearer
        expires_at:
          type: string
          format: date-time
        refresh_token:
          type: string
        session_id:
          type: string
          format: uuid
        user_id:
          type: string
          format: uuid
        tenant_id:
          type: string
          format: uuid
          nullable: true
    Principal:
      type: object
      properties:
        user_id:
          type: string
          format: uuid
          nullable: true
        tenant_id:
          type: string
          format: uuid
          nullable: true
        session_id:
          type: string
          format: uuid
          nullable: true
        actor:
          type: string
          example: user
        scopes:
          type: array
          items:
            type: string
    Session:
      type: object
      additionalProperties: true
      description: An active session (id, ip, user agent, timestamps).
    SignupRequest:
      type: object
      required:
        - email
        - password
      properties:
        email:
          type: string
          format: email
        password:
          type: string
          minLength: 8
          maxLength: 256
        display_name:
          type: string
          maxLength: 200
    SignupResponse:
      type: object
      properties:
        user:
          $ref: '#/components/schemas/User'
        access_token:
          type: string
        token_type:
          type: string
          example: Bearer
        expires_at:
          type: string
          format: date-time
        refresh_token:
          type: string
        session_id:
          type: string
          format: uuid
        user_id:
          type: string
          format: uuid
    LoginRequest:
      type: object
      required:
        - email
        - password
      properties:
        email:
          type: string
          format: email
        password:
          type: string
    RefreshRequest:
      type: object
      required:
        - refresh_token
      properties:
        refresh_token:
          type: string
    User:
      type: object
      properties:
        id:
          type: string
          format: uuid
        tenant_id:
          type: string
          format: uuid
        email:
          type: string
          format: email
        email_verified_at:
          type: string
          format: date-time
          nullable: true
        phone:
          type: string
          nullable: true
        phone_verified_at:
          type: string
          format: date-time
          nullable: true
        display_name:
          type: string
          nullable: true
        status:
          type: string
          enum:
            - active
            - suspended
        metadata:
          type: object
          additionalProperties: true
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    Role:
      type: object
      properties:
        id:
          type: string
          format: uuid
        tenant_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
        is_system:
          type: boolean
        created_at:
          type: string
          format: date-time
    GroupRole:
      type: object
      description: A role granted to a group, with the role's name for display.
      properties:
        role_id:
          type: string
          format: uuid
        name:
          type: string
        granted_at:
          type: string
          format: date-time
    AuthzGrantStep:
      type: object
      description: 'One link in an authorization decision''s grant path: a role that confers the requested permission and how that role reaches the user.'
      properties:
        permission:
          type: string
        granted_by:
          type: string
          description: The conferring role, e.g. "role:admin".
        via:
          type: string
          description: '"direct" for a user grant, or "group:<name>" for a group-derived grant.'
        group_id:
          type: string
          format: uuid
          description: Set only when via is a group grant.
        role_id:
          type: string
          format: uuid
    AuthzExplanation:
      type: object
      description: 'The structured "why?" for a single permission check: the decision plus every distinct grant (direct and group-derived) that confers it. Returned from GET /check when explain=true.'
      properties:
        allowed:
          type: boolean
        paths:
          type: array
          items:
            $ref: '#/components/schemas/AuthzGrantStep'
        reason:
          type: string
          description: Set only on a denial.
    RoleCreate:
      type: object
      required:
        - name
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 64
        description:
          type: string
          maxLength: 500
    Permission:
      type: object
      properties:
        id:
          type: string
          format: uuid
        key:
          type: string
        description:
          type: string
    Page:
      type: object
      description: Cursor-paginated list wrapper.
      properties:
        items:
          type: array
          items: {}
        next_cursor:
          type: string
          nullable: true
          description: Cursor for the next page; empty/absent at the end.
    UserCreate:
      type: object
      required:
        - tenant_id
        - email
      properties:
        tenant_id:
          type: string
          format: uuid
        email:
          type: string
          format: email
        password:
          type: string
          minLength: 8
          maxLength: 256
        display_name:
          type: string
          maxLength: 200
        phone:
          type: string
          description: E.164
        metadata:
          type: object
          additionalProperties: true
    UserUpdate:
      type: object
      properties:
        display_name:
          type: string
          maxLength: 200
          nullable: true
        phone:
          type: string
          nullable: true
        status:
          type: string
          enum:
            - active
            - suspended
        metadata:
          type: object
          additionalProperties: true
    UserPage:
      allOf:
        - $ref: '#/components/schemas/Page'
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/User'
        next_cursor:
          type: string
          nullable: true
    Tenant:
      type: object
      properties:
        id:
          type: string
          format: uuid
        slug:
          type: string
        name:
          type: string
        status:
          type: string
          enum:
            - active
            - suspended
        plan:
          type: string
          enum:
            - free
            - pro
            - enterprise
        region:
          type: string
        metadata:
          type: object
          additionalProperties: true
          nullable: true
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    TenantCreate:
      type: object
      required:
        - slug
        - name
      properties:
        slug:
          type: string
          minLength: 2
          maxLength: 64
        name:
          type: string
          minLength: 1
          maxLength: 200
        plan:
          type: string
          enum:
            - free
            - pro
            - enterprise
        region:
          type: string
          maxLength: 64
        metadata:
          type: object
          additionalProperties: true
    TenantUpdate:
      type: object
      properties:
        name:
          type: string
          minLength: 1
          maxLength: 200
        status:
          type: string
          enum:
            - active
            - suspended
        plan:
          type: string
          enum:
            - free
            - pro
            - enterprise
        region:
          type: string
          maxLength: 64
        metadata:
          type: object
          additionalProperties: true
    TenantCreateResponse:
      type: object
      properties:
        tenant:
          $ref: '#/components/schemas/Tenant'
        tenant_id:
          type: string
          format: uuid
        roles:
          type: array
          items:
            type: string
          example:
            - owner
        access_token:
          type: string
        token_type:
          type: string
        expires_at:
          type: string
          format: date-time
        refresh_token:
          type: string
        session_id:
          type: string
          format: uuid
        user_id:
          type: string
          format: uuid
    TenantPage:
      allOf:
        - $ref: '#/components/schemas/Page'
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Tenant'
        next_cursor:
          type: string
          nullable: true
    OIDCClient:
      type: object
      properties:
        id:
          type: string
          format: uuid
        tenant_id:
          type: string
          format: uuid
        client_id:
          type: string
        type:
          type: string
          enum:
            - public
            - confidential
        name:
          type: string
        redirect_uris:
          type: array
          items:
            type: string
            format: uri
        post_logout_uris:
          type: array
          items:
            type: string
            format: uri
        grant_types:
          type: array
          items:
            type: string
        scopes:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
    OIDCClientCreate:
      type: object
      required:
        - tenant_id
        - name
        - type
      properties:
        tenant_id:
          type: string
          format: uuid
        name:
          type: string
        type:
          type: string
          enum:
            - public
            - confidential
        redirect_uris:
          type: array
          items:
            type: string
            format: uri
        post_logout_uris:
          type: array
          items:
            type: string
            format: uri
        grant_types:
          type: array
          items:
            type: string
        scopes:
          type: array
          items:
            type: string
    OIDCClientUpdate:
      type: object
      description: Partial (COALESCE-style) update; omitted fields are left unchanged.
      properties:
        name:
          type: string
        redirect_uris:
          type: array
          items:
            type: string
            format: uri
        post_logout_uris:
          type: array
          items:
            type: string
            format: uri
        grant_types:
          type: array
          items:
            type: string
        scopes:
          type: array
          items:
            type: string
    OAuthDeviceAuthorization:
      type: object
      description: Admin view of an RFC 8628 device-authorization row. Never includes the device_code or its hash.
      properties:
        id:
          type: string
          format: uuid
        client_id:
          type: string
        user_code:
          type: string
        status:
          type: string
          enum:
            - pending
            - authorized
            - denied
        user_id:
          type: string
          format: uuid
          nullable: true
        user_email:
          type: string
        scopes:
          type: array
          items:
            type: string
        created_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time
        last_polled_at:
          type: string
          format: date-time
          nullable: true
    SigningKey:
      type: object
      description: Non-secret metadata for an issuer signing key (no key material).
      properties:
        kid:
          type: string
          description: RFC 7638 JWK thumbprint of the public key.
        alg:
          type: string
          example: ES256
        use:
          type: string
          example: sig
        status:
          type: string
          enum:
            - active
            - retired
    ServicePrincipalCreate:
      type: object
      required:
        - tenant_id
        - name
      properties:
        tenant_id:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
        scopes:
          type: array
          items:
            type: string
    OAuthTokenRequest:
      type: object
      required:
        - grant_type
      properties:
        grant_type:
          type: string
          enum:
            - authorization_code
            - refresh_token
            - urn:ietf:params:oauth:grant-type:device_code
        code:
          type: string
        redirect_uri:
          type: string
          format: uri
        code_verifier:
          type: string
        refresh_token:
          type: string
        device_code:
          type: string
          description: Present when grant_type is the RFC 8628 device_code grant.
        client_id:
          type: string
        client_secret:
          type: string
    DeviceAuthorizationResponse:
      type: object
      description: RFC 8628 §3.2 device authorization response.
      required:
        - device_code
        - user_code
        - verification_uri
        - expires_in
      properties:
        device_code:
          type: string
        user_code:
          type: string
          description: Human-friendly code (XXXX-XXXX) from an unambiguous alphabet.
        verification_uri:
          type: string
          format: uri
        verification_uri_complete:
          type: string
          format: uri
        expires_in:
          type: integer
        interval:
          type: integer
          description: Minimum seconds the device must wait between token polls.
    OAuthTokenResponse:
      type: object
      properties:
        access_token:
          type: string
        id_token:
          type: string
        refresh_token:
          type: string
        token_type:
          type: string
          example: Bearer
        expires_in:
          type: integer
        scope:
          type: string
    Introspection:
      type: object
      properties:
        active:
          type: boolean
      additionalProperties: true
      description: RFC 7662 response; `active` plus claims when active.
    OIDCDiscovery:
      type: object
      additionalProperties: true
      description: OIDC discovery metadata (issuer, endpoints, supported features).
    JWKS:
      type: object
      properties:
        keys:
          type: array
          items:
            type: object
            additionalProperties: true
    SAMLConnection:
      type: object
      properties:
        id:
          type: string
          format: uuid
        tenant_id:
          type: string
          format: uuid
        name:
          type: string
        idp_entity_id:
          type: string
        idp_sso_url:
          type: string
          format: uri
        idp_certificate:
          type: string
        email_attribute:
          type: string
        name_attribute:
          type: string
        status:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        last_login_at:
          type: string
          format: date-time
          nullable: true
    SAMLConnectionCreate:
      type: object
      required:
        - name
        - idp_entity_id
        - idp_sso_url
        - idp_certificate
      properties:
        name:
          type: string
        idp_entity_id:
          type: string
        idp_sso_url:
          type: string
          format: uri
        idp_certificate:
          type: string
          description: PEM or base64 DER X.509 signing certificate
        email_attribute:
          type: string
        name_attribute:
          type: string
        status:
          type: string
    SAMLServiceProvider:
      type: object
      properties:
        id:
          type: string
          format: uuid
        tenant_id:
          type: string
          format: uuid
        name:
          type: string
        entity_id:
          type: string
        acs_url:
          type: string
          format: uri
        name_id_format:
          type: string
        name_id_attribute:
          type: string
        certificate:
          type: string
        status:
          type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        last_login_at:
          type: string
          format: date-time
          nullable: true
    SAMLServiceProviderCreate:
      type: object
      required:
        - name
        - entity_id
        - acs_url
      properties:
        name:
          type: string
        entity_id:
          type: string
        acs_url:
          type: string
          format: uri
        name_id_format:
          type: string
        name_id_attribute:
          type: string
        certificate:
          type: string
    SCIMUser:
      type: object
      required:
        - schemas
      properties:
        schemas:
          type: array
          items:
            type: string
          example:
            - urn:ietf:params:scim:schemas:core:2.0:User
        id:
          type: string
        externalId:
          type: string
        userName:
          type: string
        displayName:
          type: string
        active:
          type: boolean
        name:
          type: object
          properties:
            formatted:
              type: string
            givenName:
              type: string
            familyName:
              type: string
        emails:
          type: array
          items:
            type: object
            properties:
              value:
                type: string
              primary:
                type: boolean
              type:
                type: string
        meta:
          type: object
          additionalProperties: true
    SCIMGroup:
      type: object
      required:
        - schemas
        - displayName
      properties:
        schemas:
          type: array
          items:
            type: string
          example:
            - urn:ietf:params:scim:schemas:core:2.0:Group
        id:
          type: string
        externalId:
          type: string
        displayName:
          type: string
        members:
          type: array
          items:
            type: object
            properties:
              value:
                type: string
                description: User id
              display:
                type: string
        meta:
          type: object
          additionalProperties: true
    SCIMPatchOp:
      type: object
      required:
        - schemas
        - Operations
      properties:
        schemas:
          type: array
          items:
            type: string
          example:
            - urn:ietf:params:scim:api:messages:2.0:PatchOp
        Operations:
          type: array
          items:
            type: object
            required:
              - op
            properties:
              op:
                type: string
                enum:
                  - add
                  - remove
                  - replace
              path:
                type: string
              value: {}
    SCIMListResponse:
      type: object
      properties:
        schemas:
          type: array
          items:
            type: string
          example:
            - urn:ietf:params:scim:api:messages:2.0:ListResponse
        totalResults:
          type: integer
        startIndex:
          type: integer
        itemsPerPage:
          type: integer
        Resources:
          type: array
          items:
            type: object
            additionalProperties: true
    ApiKey:
      type: object
      properties:
        id:
          type: string
          format: uuid
        tenant_id:
          type: string
          format: uuid
        user_id:
          type: string
          format: uuid
          nullable: true
        name:
          type: string
        prefix:
          type: string
        scopes:
          type: array
          items:
            type: string
        expires_at:
          type: string
          format: date-time
          nullable: true
        last_used_at:
          type: string
          format: date-time
          nullable: true
        revoked_at:
          type: string
          format: date-time
          nullable: true
        created_at:
          type: string
          format: date-time
    ApiKeyCreate:
      type: object
      required:
        - tenant_id
        - name
      properties:
        tenant_id:
          type: string
          format: uuid
        user_id:
          type: string
          format: uuid
          nullable: true
        name:
          type: string
          minLength: 1
          maxLength: 200
        scopes:
          type: array
          items:
            type: string
        expires_at:
          type: string
          format: date-time
          nullable: true
    RateLimitBucket:
      type: object
      description: A single token-bucket limit (rate tokens/sec, burst capacity).
      properties:
        rate:
          type: number
          description: Sustained tokens per second.
        capacity:
          type: integer
          description: Maximum burst capacity.
    TenantRateLimits:
      type: object
      description: Per-bucket rate limits for a tenant. On GET these are the effective values (defaults merged with overrides); on PUT, any bucket supplied is upserted as an override.
      properties:
        tenant:
          $ref: '#/components/schemas/RateLimitBucket'
        user:
          $ref: '#/components/schemas/RateLimitBucket'
        api_key:
          $ref: '#/components/schemas/RateLimitBucket'
  parameters:
    Limit:
      name: limit
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 200
      description: Maximum items to return.
    Cursor:
      name: cursor
      in: query
      required: false
      schema:
        type: string
      description: Opaque pagination cursor from a prior response's next_cursor.
