openapi: 3.0.3
info:
  title: ContextHub API
  description: Multi-tenant headless CMS and content services platform API documentation
  version: 0.1.0
  contact:
    name: ContextHub Support
    email: support@ctxhub.net
  license:
    name: MIT
    url: https://opensource.org/licenses/MIT
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: JWT token from /api/auth/login endpoint
    apiToken:
      type: apiKey
      in: header
      name: Authorization
      description: "API Token for Content-as-a-Service access. Format: Bearer
        ctx_your_token_here"
    apiKey:
      type: apiKey
      in: header
      name: X-API-Key
      description: "API Key for public form submissions. Format: ctx_your_key_here"
    tenantId:
      type: apiKey
      in: header
      name: X-Tenant-ID
      description: Tenant ID for multi-tenant operations
  schemas: {}
paths:
  /api/auth/login:
    post:
      summary: User login
      tags:
        - auth
      description: Authenticate user with email and password
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                  description: User email address
                password:
                  type: string
                  minLength: 1
                  description: User password
                tenantId:
                  type: string
                  description: Optional tenant ID for multi-tenant login
              required:
                - email
                - password
        required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                      email:
                        type: string
                      firstName:
                        type: string
                      lastName:
                        type: string
                      mustChangePassword:
                        type: boolean
                      role:
                        type: string
                        nullable: true
                      permissions:
                        type: array
                        items:
                          type: string
                  csrfToken:
                    type: string
                  memberships:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        tenantId:
                          type: string
                        tenant:
                          type: object
                          properties:
                            id:
                              type: string
                            name:
                              type: string
                            slug:
                              type: string
                        role:
                          type: string
                        roleMeta:
                          type: object
                          nullable: true
                          properties:
                            id:
                              type: string
                            key:
                              type: string
                            name:
                              type: string
                            description:
                              type: string
                            level:
                              type: number
                            permissions:
                              type: array
                              items:
                                type: string
                            tenantId:
                              type: string
                            isDefault:
                              type: boolean
                            isSystem:
                              type: boolean
                        status:
                          type: string
                        permissions:
                          type: array
                          items:
                            type: string
                  requiresTenantSelection:
                    type: boolean
                  message:
                    type: string
                  activeMembership:
                    type: object
                    nullable: true
                    properties:
                      id:
                        type: string
                      tenantId:
                        type: string
                      tenant:
                        type: object
                        properties:
                          id:
                            type: string
                          name:
                            type: string
                          slug:
                            type: string
                      role:
                        type: string
                      roleMeta:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          key:
                            type: string
                          name:
                            type: string
                          description:
                            type: string
                          level:
                            type: number
                          permissions:
                            type: array
                            items:
                              type: string
                          tenantId:
                            type: string
                          isDefault:
                            type: boolean
                          isSystem:
                            type: boolean
                      status:
                        type: string
                      permissions:
                        type: array
                        items:
                          type: string
  /api/auth/register:
    post:
      summary: User registration
      tags:
        - auth
      description: Register a new user without tenant provisioning
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                email:
                  type: string
                  format: email
                  description: User email address
                password:
                  type: string
                  minLength: 6
                  description: Password (minimum 6 characters)
                firstName:
                  type: string
                  minLength: 1
                  description: User first name
                lastName:
                  type: string
                  minLength: 1
                  description: User last name
              required:
                - email
                - password
                - firstName
                - lastName
        required: true
      responses:
        "201":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                      email:
                        type: string
                      firstName:
                        type: string
                      lastName:
                        type: string
                  tenant:
                    type: object
                    nullable: true
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      slug:
                        type: string
  /api/auth/refresh:
    post:
      summary: Token refresh
      tags:
        - auth
      description: Refresh an existing JWT token
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties: {}
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  csrfToken:
                    type: string
                  role:
                    type: string
                    nullable: true
                  permissions:
                    type: array
                    items:
                      type: string
  /api/auth/invitations/preview:
    get:
      summary: Preview invitation
      tags:
        - auth
      description: Preview a tenant invitation before accepting it
      parameters:
        - schema:
            type: string
            minLength: 10
          in: query
          name: token
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  email:
                    type: string
                    nullable: true
                  firstName:
                    type: string
                  lastName:
                    type: string
                  role:
                    type: string
                  status:
                    type: string
                  expiresAt:
                    type: string
                  requiresPasswordSetup:
                    type: boolean
                  requiresProfileSetup:
                    type: boolean
                  requiresAuthentication:
                    type: boolean
                  tenant:
                    type: object
                    nullable: true
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      slug:
                        type: string
                      plan:
                        type: string
                      status:
                        type: string
  /api/auth/invitations/accept:
    post:
      summary: Accept invitation
      tags:
        - auth
      description: Accept a tenant invitation and create/update user account
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                token:
                  type: string
                  minLength: 10
                password:
                  type: string
                  minLength: 6
                firstName:
                  type: string
                  minLength: 1
                lastName:
                  type: string
                  minLength: 1
              required:
                - token
        required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  csrfToken:
                    type: string
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                      email:
                        type: string
                      firstName:
                        type: string
                      lastName:
                        type: string
                      mustChangePassword:
                        type: boolean
                      role:
                        type: string
                      permissions:
                        type: array
                        items:
                          type: string
                  membership:
                    type: object
                    properties:
                      id:
                        type: string
                      tenantId:
                        type: string
                      tenant:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          name:
                            type: string
                          slug:
                            type: string
                          plan:
                            type: string
                          status:
                            type: string
                      role:
                        type: string
                      roleMeta:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          key:
                            type: string
                          name:
                            type: string
                          description:
                            type: string
                          level:
                            type: number
                          permissions:
                            type: array
                            items:
                              type: string
                      permissions:
                        type: array
                        items:
                          type: string
                      status:
                        type: string
                      acceptedAt:
                        type: string
                  activeMembership:
                    type: object
                    properties:
                      id:
                        type: string
                      tenantId:
                        type: string
                      tenant:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          name:
                            type: string
                          slug:
                            type: string
                          plan:
                            type: string
                          status:
                            type: string
                          createdAt:
                            type: string
                      role:
                        type: string
                      roleMeta:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          key:
                            type: string
                          name:
                            type: string
                          description:
                            type: string
                          level:
                            type: number
                          permissions:
                            type: array
                            items:
                              type: string
                      permissions:
                        type: array
                        items:
                          type: string
                      status:
                        type: string
                  memberships:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        tenantId:
                          type: string
                        tenant:
                          type: object
                          nullable: true
                          properties:
                            id:
                              type: string
                            name:
                              type: string
                            slug:
                              type: string
                            plan:
                              type: string
                            status:
                              type: string
                            createdAt:
                              type: string
                        role:
                          type: string
                        roleMeta:
                          type: object
                          nullable: true
                          properties:
                            id:
                              type: string
                            key:
                              type: string
                            name:
                              type: string
                            description:
                              type: string
                            level:
                              type: number
                            permissions:
                              type: array
                              items:
                                type: string
                        permissions:
                          type: array
                          items:
                            type: string
                        status:
                          type: string
  /api/auth/logout:
    post:
      summary: User logout
      tags:
        - auth
      description: Logout user and revoke the current token
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
  /api/auth/logout-all:
    post:
      summary: Logout from all devices
      tags:
        - auth
      description: Revoke all sessions for the current user
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
  /api/auth/session:
    get:
      summary: Current session
      tags:
        - auth
      description: Return the current cookie-backed session state
      responses:
        "200":
          description: Default Response
  /api/auth/switch-tenant:
    post:
      summary: Switch tenant
      tags:
        - auth
      description: Switch the active tenant and rotate the session
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                tenantId:
                  type: string
                  minLength: 1
              required:
                - tenantId
        required: true
      responses:
        "200":
          description: Default Response
  /api/auth/forgot-password:
    post:
      summary: Forgot password
      tags:
        - auth
      description: Request a password reset email
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
              required:
                - email
        required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
  /api/auth/reset-password:
    post:
      summary: Reset password
      tags:
        - auth
      description: Reset password using token from email
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                token:
                  type: string
                  minLength: 1
                password:
                  type: string
                  minLength: 6
              required:
                - token
                - password
        required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
  /api/auth/verify-email:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                token:
                  type: string
                  minLength: 1
              required:
                - token
        required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                  verified:
                    type: boolean
                  alreadyVerified:
                    type: boolean
        "400":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/auth/resend-verification:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
              required:
                - email
        required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        "400":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/users:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
        - schema:
            type: number
            default: 1
          in: query
          name: page
          required: false
        - schema:
            type: number
            default: 10
          in: query
          name: limit
          required: false
        - schema:
            type: string
          in: query
          name: search
          required: false
        - schema:
            type: string
          in: query
          name: status
          required: false
        - schema:
            type: string
          in: query
          name: role
          required: false
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  users:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        email:
                          type: string
                        firstName:
                          type: string
                        lastName:
                          type: string
                        role:
                          type: string
                        status:
                          type: string
                        createdAt:
                          type: string
                        lastLoginAt:
                          type: string
                  pagination:
                    type: object
                    properties:
                      page:
                        type: number
                      limit:
                        type: number
                      total:
                        type: number
                      pages:
                        type: number
                      offset:
                        type: number
                      hasPrevPage:
                        type: boolean
                      hasNextPage:
                        type: boolean
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                email:
                  type: string
                  format: email
                role:
                  type: string
              required:
                - email
                - role
        required: true
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
  /api/users/{id}:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                firstName:
                  type: string
                  minLength: 1
                lastName:
                  type: string
                  minLength: 1
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/users/{id}/role:
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                role:
                  type: string
              required:
                - role
        required: true
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/users/{id}/toggle-status:
    patch:
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  membership:
                    type: object
                    properties:
                      id:
                        type: string
                      role:
                        type: string
                      status:
                        type: string
  /api/users/me:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: false
      responses:
        "200":
          description: Default Response
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                firstName:
                  type: string
                  minLength: 1
                lastName:
                  type: string
                  minLength: 1
                email:
                  type: string
                  format: email
                language:
                  type:
                    - string
                    - "null"
                  enum:
                    - tr
                    - en
                    - null
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  user:
                    type: object
                    properties:
                      id:
                        type: string
                      email:
                        type: string
                      firstName:
                        type: string
                      lastName:
                        type: string
                      language:
                        type:
                          - "null"
                          - string
    delete:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
        "400":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/users/me/password:
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                currentPassword:
                  type: string
                  minLength: 1
                newPassword:
                  type: string
                  minLength: 6
              required:
                - currentPassword
                - newPassword
        required: true
      responses:
        "200":
          description: Default Response
  /api/users/invite:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                email:
                  type: string
                  format: email
                role:
                  type: string
              required:
                - email
                - role
        required: true
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
  /api/users/{id}/reinvite:
    post:
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/memberships/{id}/leave:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                password:
                  type: string
                  minLength: 1
              required:
                - password
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/tenants:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                name:
                  type: string
                  minLength: 1
                slug:
                  type: string
                  minLength: 1
              required:
                - name
        required: true
      responses:
        "201":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  tenant:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      slug:
                        type: string
                      plan:
                        type: string
                      status:
                        type: string
                      createdAt:
                        type: string
                  membership:
                    type: object
                    properties:
                      id:
                        type: string
                      role:
                        type: string
                      roleMeta:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          key:
                            type: string
                          name:
                            type: string
                          description:
                            type: string
                          level:
                            type: number
                          permissions:
                            type: array
                            items:
                              type: string
                      permissions:
                        type: array
                        items:
                          type: string
                      status:
                        type: string
                  csrfToken:
                    type: string
    get:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  tenants:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        tenantId:
                          type: string
                        tenant:
                          type: object
                          properties:
                            id:
                              type: string
                            name:
                              type: string
                            slug:
                              type: string
                            plan:
                              type: string
                            status:
                              type: string
                            createdAt:
                              type: string
                        role:
                          type: string
                        roleMeta:
                          type: object
                          nullable: true
                          properties:
                            id:
                              type: string
                            key:
                              type: string
                            name:
                              type: string
                            description:
                              type: string
                            level:
                              type: number
                            permissions:
                              type: array
                              items:
                                type: string
                        permissions:
                          type: array
                          items:
                            type: string
                        status:
                          type: string
                        ownerCount:
                          type: number
  /api/tenants/{id}/accept:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  membership:
                    type: object
                    properties:
                      id:
                        type: string
                      tenantId:
                        type: string
                      role:
                        type: string
                      roleMeta:
                        type: object
                        nullable: true
                        properties:
                          id:
                            type: string
                          key:
                            type: string
                          name:
                            type: string
                          description:
                            type: string
                          level:
                            type: number
                          permissions:
                            type: array
                            items:
                              type: string
                      permissions:
                        type: array
                        items:
                          type: string
                      status:
                        type: string
                      acceptedAt:
                        type: string
                  tenant:
                    type: object
                    nullable: true
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      slug:
                        type: string
                      plan:
                        type: string
                      status:
                        type: string
                  csrfToken:
                    type: string
  /api/tenants/{id}/transfer-ownership:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                email:
                  type: string
                  format: email
                password:
                  type: string
                  minLength: 1
              required:
                - email
                - password
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/tenants/{id}/accept-transfer:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                token:
                  type: string
                  minLength: 1
              required:
                - token
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/tenant/info:
    get:
      tags:
        - tenant
      description: Get current tenant public information and brand settings
      security:
        - bearerAuth: []
        - apiToken: []
      responses:
        "200":
          description: Tenant information
          content:
            application/json:
              schema:
                description: Tenant information
                type: object
                properties:
                  tenant:
                    type: object
                    properties:
                      id:
                        type: string
                      name:
                        type: string
                      slug:
                        type: string
                      plan:
                        type: string
                      status:
                        type: string
                  branding:
                    type: object
                    nullable: true
                    properties:
                      name:
                        type: string
                        nullable: true
                      siteName:
                        type: string
                        nullable: true
                      description:
                        type: string
                        nullable: true
                      logo:
                        type: string
                        nullable: true
                      logoUrl:
                        type: string
                        nullable: true
                      favicon:
                        type: string
                        nullable: true
                      faviconUrl:
                        type: string
                        nullable: true
                      primaryColor:
                        type: string
                        nullable: true
                      secondaryColor:
                        type: string
                        nullable: true
                  metadata:
                    type: object
                    nullable: true
                    additionalProperties: true
                    description: Custom metadata key-value pairs
  /api/tenant-settings:
    get:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  settings:
                    type: object
                    properties:
                      tenantId:
                        type: string
                      createdAt:
                        type: string
                        nullable: true
                      updatedAt:
                        type: string
                        nullable: true
                      smtp:
                        type: object
                        properties:
                          enabled:
                            type: boolean
                          host:
                            type: string
                          port:
                            type: number
                            nullable: true
                          secure:
                            type: boolean
                          username:
                            type: string
                          fromName:
                            type: string
                          fromEmail:
                            type: string
                          hasPassword:
                            type: boolean
                        additionalProperties: false
                      webhook:
                        type: object
                        properties:
                          enabled:
                            type: boolean
                          url:
                            type: string
                          hasSecret:
                            type: boolean
                        additionalProperties: false
                      branding:
                        type: object
                        properties:
                          siteName:
                            type: string
                          logoUrl:
                            type: string
                          primaryColor:
                            type: string
                          secondaryColor:
                            type: string
                          description:
                            type: string
                        additionalProperties: false
                      limits:
                        type: object
                        properties:
                          entries:
                            type: number
                            nullable: true
                          media:
                            type: number
                            nullable: true
                          users:
                            type: number
                            nullable: true
                          apiCalls:
                            type: number
                            nullable: true
                          emailPerMonth:
                            type: number
                            nullable: true
                          custom:
                            type: object
                            additionalProperties:
                              type: number
                              nullable: true
                        additionalProperties: false
                      edgeGateway:
                        type: object
                        properties:
                          publicReadEnabled:
                            type: boolean
                          allowLocalhost:
                            type: boolean
                          allowedOrigins:
                            type: array
                            items:
                              type: string
                        additionalProperties: false
                      features:
                        type: object
                        additionalProperties:
                          type: boolean
                      metadata:
                        type: object
                        additionalProperties: true
                    additionalProperties: false
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                smtp:
                  type: object
                  properties:
                    enabled:
                      type: boolean
                    host:
                      type: string
                      nullable: true
                    port:
                      type: number
                      nullable: true
                    secure:
                      type: boolean
                    username:
                      type: string
                      nullable: true
                    password:
                      type: string
                      nullable: true
                    fromName:
                      type: string
                      nullable: true
                    fromEmail:
                      type: string
                      nullable: true
                  additionalProperties: false
                webhook:
                  type: object
                  properties:
                    enabled:
                      type: boolean
                    url:
                      type: string
                      nullable: true
                    secret:
                      type: string
                      nullable: true
                  additionalProperties: false
                branding:
                  type: object
                  properties:
                    siteName:
                      type: string
                      nullable: true
                    logoUrl:
                      type: string
                      nullable: true
                    primaryColor:
                      type: string
                      nullable: true
                    secondaryColor:
                      type: string
                      nullable: true
                    description:
                      type: string
                      nullable: true
                  additionalProperties: false
                limits:
                  type: object
                  properties:
                    entries:
                      type: number
                      nullable: true
                    media:
                      type: number
                      nullable: true
                    users:
                      type: number
                      nullable: true
                    apiCalls:
                      type: number
                      nullable: true
                    emailPerMonth:
                      type: number
                      nullable: true
                    custom:
                      type: object
                      additionalProperties:
                        type: number
                        nullable: true
                  additionalProperties: false
                edgeGateway:
                  type: object
                  properties:
                    publicReadEnabled:
                      type: boolean
                    allowLocalhost:
                      type: boolean
                    allowedOrigins:
                      type: array
                      items:
                        type: string
                  additionalProperties: false
                features:
                  type: object
                  additionalProperties:
                    type: boolean
                metadata:
                  type: object
                  additionalProperties: true
              additionalProperties: false
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  settings:
                    type: object
                    properties:
                      tenantId:
                        type: string
                      createdAt:
                        type: string
                        nullable: true
                      updatedAt:
                        type: string
                        nullable: true
                      smtp:
                        type: object
                        properties:
                          enabled:
                            type: boolean
                          host:
                            type: string
                          port:
                            type: number
                            nullable: true
                          secure:
                            type: boolean
                          username:
                            type: string
                          fromName:
                            type: string
                          fromEmail:
                            type: string
                          hasPassword:
                            type: boolean
                        additionalProperties: false
                      webhook:
                        type: object
                        properties:
                          enabled:
                            type: boolean
                          url:
                            type: string
                          hasSecret:
                            type: boolean
                        additionalProperties: false
                      branding:
                        type: object
                        properties:
                          siteName:
                            type: string
                          logoUrl:
                            type: string
                          primaryColor:
                            type: string
                          secondaryColor:
                            type: string
                          description:
                            type: string
                        additionalProperties: false
                      limits:
                        type: object
                        properties:
                          entries:
                            type: number
                            nullable: true
                          media:
                            type: number
                            nullable: true
                          users:
                            type: number
                            nullable: true
                          apiCalls:
                            type: number
                            nullable: true
                          emailPerMonth:
                            type: number
                            nullable: true
                          custom:
                            type: object
                            additionalProperties:
                              type: number
                              nullable: true
                        additionalProperties: false
                      edgeGateway:
                        type: object
                        properties:
                          publicReadEnabled:
                            type: boolean
                          allowLocalhost:
                            type: boolean
                          allowedOrigins:
                            type: array
                            items:
                              type: string
                        additionalProperties: false
                      features:
                        type: object
                        additionalProperties:
                          type: boolean
                      metadata:
                        type: object
                        additionalProperties: true
                    additionalProperties: false
  /api/activities:
    get:
      parameters:
        - schema:
            type: integer
            minimum: 1
            default: 1
          in: query
          name: page
          required: false
        - schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 20
          in: query
          name: limit
          required: false
        - schema:
            type: string
          in: query
          name: action
          required: false
        - schema:
            type: string
          in: query
          name: userId
          required: false
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  activities:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        user:
                          type: object
                          properties:
                            id:
                              type: string
                            firstName:
                              type: string
                            lastName:
                              type: string
                            email:
                              type: string
                        action:
                          type: string
                        description:
                          type: string
                        metadata:
                          type: object
                        ipAddress:
                          type: string
                        createdAt:
                          type: string
                  pagination:
                    type: object
                    properties:
                      page:
                        type: integer
                      limit:
                        type: integer
                      total:
                        type: integer
                      totalPages:
                        type: integer
  /api/activities/recent:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: tenantId
          required: true
        - schema:
            type: integer
            minimum: 1
            maximum: 50
            default: 10
          in: query
          name: limit
          required: false
      responses:
        "200":
          description: Default Response
  /api/media/presign:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                fileName:
                  type: string
                contentType:
                  type: string
                size:
                  type: number
                  minimum: 1
              required:
                - fileName
                - contentType
                - size
        required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  uploadUrl:
                    type: string
                  key:
                    type: string
                  fileName:
                    type: string
                  folder:
                    type: string
                  bucket:
                    type: string
                  publicUrl:
                    type: string
                    nullable: true
                  extension:
                    type: string
                    nullable: true
                  maxUploadBytes:
                    type: number
  /api/media:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                key:
                  type: string
                originalName:
                  type: string
                mimeType:
                  type: string
                size:
                  type: number
                altText:
                  type: string
                caption:
                  type: string
                description:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
              required:
                - key
        required: true
      responses:
        "200":
          description: Default Response
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: search
          required: false
        - schema:
            type: string
          in: query
          name: mimeType
          required: false
        - schema:
            anyOf:
              - type: array
                items:
                  type: string
              - type: string
          in: query
          name: tags
          required: false
        - schema:
            type: string
          in: query
          name: status
          required: false
        - schema:
            type: number
          in: query
          name: page
          required: false
        - schema:
            type: number
          in: query
          name: limit
          required: false
      responses:
        "200":
          description: Default Response
  /api/media/register-existing:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                key:
                  type: string
                sourceUrl:
                  type: string
                originalName:
                  type: string
                mimeType:
                  type: string
                size:
                  type: number
                altText:
                  type: string
                caption:
                  type: string
                description:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
      responses:
        "200":
          description: Default Response
  /api/media/external:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                title:
                  type: string
                  nullable: true
                description:
                  type: string
                  nullable: true
                tags:
                  anyOf:
                    - type: array
                      items:
                        type: string
                    - type: string
                provider:
                  type: string
                  nullable: true
                providerId:
                  type: string
                  nullable: true
                thumbnailUrl:
                  type: string
                  nullable: true
                altText:
                  type: string
                  nullable: true
                duration:
                  type: number
                  nullable: true
              required:
                - url
        required: true
      responses:
        "200":
          description: Default Response
  /api/media/{id}:
    patch:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                originalName:
                  type: string
                altText:
                  type: string
                caption:
                  type: string
                description:
                  type: string
                tags:
                  type: array
                  items:
                    type: string
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/media/bulk/tags:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  items:
                    type: string
                  minItems: 1
                tags:
                  type: array
                  items:
                    type: string
                  minItems: 1
                mode:
                  type: string
                  enum:
                    - add
                    - replace
              required:
                - ids
                - tags
        required: true
      responses:
        "200":
          description: Default Response
  /api/media/bulk/delete:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                ids:
                  type: array
                  items:
                    type: string
                  minItems: 1
              required:
                - ids
        required: true
      responses:
        "200":
          description: Default Response
  /api/categories:
    get:
      parameters:
        - schema:
            type:
              - boolean
              - string
          in: query
          name: flat
          required: false
        - schema:
            type: string
          in: query
          name: search
          required: false
        - schema:
            type:
              - number
              - string
          in: query
          name: page
          required: false
        - schema:
            type:
              - number
              - string
          in: query
          name: limit
          required: false
        - schema:
            anyOf:
              - type: array
                items:
                  type: string
              - type: string
          in: query
          name: ids
          required: false
      responses:
        "200":
          description: Default Response
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                slug:
                  type: string
                description:
                  type: string
                parentId:
                  type: string
                  nullable: true
                defaultSortField:
                  type: string
                defaultSortOrder:
                  type: string
                  enum:
                    - asc
                    - desc
                position:
                  type: number
                settings:
                  type: object
                  additionalProperties: true
                metadata:
                  type: object
                  additionalProperties: true
              required:
                - name
        required: true
      responses:
        "200":
          description: Default Response
  /api/categories/{id}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                slug:
                  type: string
                description:
                  type: string
                parentId:
                  type: string
                  nullable: true
                defaultSortField:
                  type: string
                defaultSortOrder:
                  type: string
                  enum:
                    - asc
                    - desc
                position:
                  type: number
                settings:
                  type: object
                  additionalProperties: true
                metadata:
                  type: object
                  additionalProperties: true
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type:
              - boolean
              - string
          in: query
          name: cascade
          required: false
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/categories/merge:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                sourceId:
                  type: string
                targetId:
                  type: string
              required:
                - sourceId
                - targetId
        required: true
      responses:
        "200":
          description: Default Response
  /api/tags:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: search
          required: false
        - schema:
            type:
              - number
              - string
          in: query
          name: page
          required: false
        - schema:
            type:
              - number
              - string
          in: query
          name: limit
          required: false
        - schema:
            anyOf:
              - type: array
                items:
                  type: string
              - type: string
          in: query
          name: ids
          required: false
      responses:
        "200":
          description: Default Response
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
              required:
                - title
        required: true
      responses:
        "200":
          description: Default Response
  /api/custom-field-definitions:
    get:
      responses:
        "200":
          description: Default Response
    post:
      responses:
        "200":
          description: Default Response
  /api/custom-field-definitions/{id}:
    put:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/contents:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: status
          required: false
          description: Filter by content status (draft, published, scheduled, archived)
        - schema:
            type: string
          in: query
          name: search
          required: false
          description: Search in title and summary fields (partial match), plus exact
            match on slug
        - schema:
            type: string
          in: query
          name: category
          required: false
          description: Filter by category ID (single)
        - schema:
            type: string
          in: query
          name: categories
          required: false
          description: "Filter by category IDs (comma-separated: id1,id2,id3)"
        - schema:
            type: string
          in: query
          name: categoryName
          required: false
          description: Search categories by name
        - schema:
            type: string
          in: query
          name: tag
          required: false
          description: Filter by tag ID (single or comma-separated)
        - schema:
            type: string
          in: query
          name: tagName
          required: false
          description: Search tags by name/title
        - schema:
            type: string
          in: query
          name: publishedFrom
          required: false
          description: Filter contents published after or on this ISO date
        - schema:
            type: string
          in: query
          name: publishedTo
          required: false
          description: Filter contents published before or on this ISO date
        - schema:
            type: number
          in: query
          name: page
          required: false
          description: "Page number (default: 1)"
        - schema:
            type: number
          in: query
          name: limit
          required: false
          description: "Items per page (default: 20, max: 100)"
      responses:
        "200":
          description: Default Response
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                slug:
                  type: string
                  maxLength: 240
                summary:
                  type: string
                lexical:
                  type: object
                html:
                  type: string
                categories:
                  type: array
                  items:
                    type: string
                tags:
                  type: array
                  items:
                    type: string
                customFields:
                  type: object
                  additionalProperties: true
                featuredMediaId:
                  type: string
                  nullable: true
                status:
                  type: string
                publishAt:
                  type:
                    - string
                    - "null"
                authorName:
                  type: string
              required:
                - title
        required: true
      responses:
        "200":
          description: Default Response
  /api/contents/check-slug:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: slug
          required: true
        - schema:
            type: string
            nullable: true
          in: query
          name: contentId
          required: false
      responses:
        "200":
          description: Default Response
  /api/contents/slug/{slug}:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: status
          required: false
          description: Optional content status filter (single or comma-separated)
        - schema:
            type: string
          in: query
          name: publishedFrom
          required: false
          description: Inclusive ISO timestamp to filter publishedAt
        - schema:
            type: string
          in: query
          name: publishedTo
          required: false
          description: Inclusive ISO timestamp to filter publishedAt
        - schema:
            type: string
          in: path
          name: slug
          required: true
      responses:
        "200":
          description: Default Response
  /api/contents/{id}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                slug:
                  type: string
                  maxLength: 240
                summary:
                  type: string
                lexical:
                  type: object
                html:
                  type: string
                categories:
                  type: array
                  items:
                    type: string
                tags:
                  type: array
                  items:
                    type: string
                customFields:
                  type: object
                  additionalProperties: true
                featuredMediaId:
                  type: string
                  nullable: true
                status:
                  type: string
                publishAt:
                  type:
                    - string
                    - "null"
                authorName:
                  type: string
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/contents/{id}/versions:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/contents/{id}/versions/delete:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                versionIds:
                  type: array
                  items:
                    type: string
                  minItems: 1
              required:
                - versionIds
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/contents/{id}/galleries:
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                galleryIds:
                  type: array
                  items:
                    type: string
              required:
                - galleryIds
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/contents/archive/statistics:
    get:
      parameters:
        - schema:
            type: string
            enum:
              - draft
              - published
              - scheduled
              - archived
          in: query
          name: status
          required: false
          description: "Filter by content status (default: published)"
      responses:
        "200":
          description: Default Response
  /api/forms:
    get:
      parameters:
        - schema:
            type: string
            enum:
              - draft
              - published
              - archived
          in: query
          name: status
          required: false
        - schema:
            type: string
          in: query
          name: search
          required: false
        - schema:
            type: number
            minimum: 1
          in: query
          name: page
          required: false
        - schema:
            type: number
            minimum: 1
            maximum: 100
          in: query
          name: limit
          required: false
      responses:
        "200":
          description: Default Response
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
              properties:
                title:
                  type:
                    - string
                    - object
                slug:
                  type: string
                description:
                  type:
                    - string
                    - object
                fields:
                  type: array
                settings:
                  type: object
                  additionalProperties: true
                visibility:
                  type: string
                  enum:
                    - public
                    - authenticated
              required:
                - title
        required: true
      responses:
        "200":
          description: Default Response
  /api/forms/{id}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: true
              properties:
                title:
                  type:
                    - string
                    - object
                slug:
                  type: string
                description:
                  type:
                    - string
                    - object
                fields:
                  type: array
                settings:
                  type: object
                  additionalProperties: true
                visibility:
                  type: string
                  enum:
                    - public
                    - authenticated
                status:
                  type: string
                  enum:
                    - draft
                    - published
                    - archived
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/forms/{id}/publish:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/forms/{id}/archive:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/forms/{id}/versions:
    get:
      parameters:
        - schema:
            type: number
            minimum: 1
          in: query
          name: page
          required: false
        - schema:
            type: number
            minimum: 1
            maximum: 100
          in: query
          name: limit
          required: false
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/forms/{id}/restore/{version}:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
        - schema:
            type: number
            minimum: 1
          in: path
          name: version
          required: true
      responses:
        "200":
          description: Default Response
  /api/forms/{id}/duplicate:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/forms/check-slug:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: slug
          required: true
        - schema:
            type: string
          in: query
          name: formId
          required: false
      responses:
        "200":
          description: Default Response
  /api/forms/{id}/responses:
    get:
      tags:
        - forms
      description: Get all form responses with filtering and pagination
      parameters:
        - schema:
            type: string
            enum:
              - pending
              - processed
              - spam
              - deleted
          in: query
          name: status
          required: false
          description: Filter by response status
        - schema:
            type: string
            format: date-time
          in: query
          name: startDate
          required: false
          description: Filter responses from this date
        - schema:
            type: string
            format: date-time
          in: query
          name: endDate
          required: false
          description: Filter responses until this date
        - schema:
            type: number
            minimum: 1
            default: 1
          in: query
          name: page
          required: false
          description: Page number
        - schema:
            type: number
            minimum: 1
            maximum: 100
            default: 20
          in: query
          name: limit
          required: false
          description: Items per page
        - schema:
            type: string
          in: path
          name: id
          required: true
          description: Form ID
      security:
        - bearerAuth: []
      responses:
        "200":
          description: List of form responses with field metadata
          content:
            application/json:
              schema:
                description: List of form responses with field metadata
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                      properties:
                        _id:
                          type: string
                        formId:
                          type: string
                        formVersion:
                          type: number
                        data:
                          type: object
                          additionalProperties: true
                          description: Form field data (field names as keys)
                        status:
                          type: string
                          enum:
                            - pending
                            - processed
                            - spam
                            - deleted
                        source:
                          type: string
                        locale:
                          type: string
                        ip:
                          type: string
                          description: Hashed IP address
                        userAgent:
                          type: string
                        createdAt:
                          type: string
                          format: date-time
                        updatedAt:
                          type: string
                          format: date-time
                        fieldMetadata:
                          type: object
                          additionalProperties: true
                          description: Field metadata mapping (field name -> { id, type, label, options })
                  pagination:
                    type: object
                    properties:
                      page:
                        type: number
                      limit:
                        type: number
                      total:
                        type: number
                      pages:
                        type: number
                  form:
                    type: object
                    additionalProperties: true
                    description: Form definition for reference
                    properties:
                      id:
                        type: string
                      title:
                        type: object
                        additionalProperties: true
                        description: Multilingual form title
                      fields:
                        type: array
                        description: Complete form field definitions
        "404":
          description: Form not found
          content:
            application/json:
              schema:
                description: Form not found
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/forms/{id}/responses/{responseId}:
    get:
      tags:
        - forms
      description: Get detailed information about a specific form response
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
          description: Form ID
        - schema:
            type: string
          in: path
          name: responseId
          required: true
          description: Response ID
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Form response details with field metadata
          content:
            application/json:
              schema:
                description: Form response details with field metadata
                type: object
                properties:
                  response:
                    type: object
                    additionalProperties: true
                    properties:
                      _id:
                        type: string
                      tenantId:
                        type: string
                      formId:
                        type: string
                      formVersion:
                        type: number
                      data:
                        type: object
                        additionalProperties: true
                        description: Form field data (field names as keys)
                      status:
                        type: string
                      source:
                        type: string
                      locale:
                        type: string
                      userAgent:
                        type: string
                      ip:
                        type: string
                        description: Hashed IP address
                      geo:
                        type: object
                        nullable: true
                        additionalProperties: true
                        properties:
                          country:
                            type: string
                          city:
                            type: string
                      device:
                        type: object
                        nullable: true
                        additionalProperties: true
                        properties:
                          type:
                            type: string
                          os:
                            type: string
                          browser:
                            type: string
                      userId:
                        type: string
                        nullable: true
                      userEmail:
                        type: string
                        nullable: true
                      userName:
                        type: string
                        nullable: true
                      createdAt:
                        type: string
                        format: date-time
                      updatedAt:
                        type: string
                        format: date-time
                      fieldMetadata:
                        type: object
                        additionalProperties: true
                        description: Field metadata mapping (field name -> { id, type, label,
                          placeholder, helpText, options, required })
                      form:
                        type: object
                        additionalProperties: true
                        description: Form definition for reference
                        properties:
                          id:
                            type: string
                          title:
                            type: object
                            additionalProperties: true
                            description: Multilingual form title
                          fields:
                            type: array
                            description: Complete form field definitions
        "404":
          description: Response not found
          content:
            application/json:
              schema:
                description: Response not found
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
    delete:
      tags:
        - forms
      description: Delete a form response (soft delete, sets status to deleted)
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
          description: Form ID
        - schema:
            type: string
          in: path
          name: responseId
          required: true
          description: Response ID
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Response deleted successfully
          content:
            application/json:
              schema:
                description: Response deleted successfully
                type: object
                properties:
                  success:
                    type: boolean
                  response:
                    type: object
                    properties:
                      _id:
                        type: string
                      status:
                        type: string
                        enum:
                          - deleted
        "404":
          description: Response not found
          content:
            application/json:
              schema:
                description: Response not found
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/forms/{id}/responses/{responseId}/permanent:
    delete:
      tags:
        - forms
      description: Permanently delete a form response from database (hard delete,
        cannot be undone)
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
          description: Form ID
        - schema:
            type: string
          in: path
          name: responseId
          required: true
          description: Response ID
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Response permanently deleted
          content:
            application/json:
              schema:
                description: Response permanently deleted
                type: object
                properties:
                  success:
                    type: boolean
                  responseId:
                    type: string
        "404":
          description: Response not found
          content:
            application/json:
              schema:
                description: Response not found
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/forms/{id}/responses/{responseId}/status:
    patch:
      tags:
        - forms
      description: Update form response status
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                status:
                  type: string
                  enum:
                    - pending
                    - processed
                    - spam
                    - deleted
                  description: New status for the response
              required:
                - status
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
          description: Form ID
        - schema:
            type: string
          in: path
          name: responseId
          required: true
          description: Response ID
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Status updated successfully
          content:
            application/json:
              schema:
                description: Status updated successfully
                type: object
                properties:
                  success:
                    type: boolean
                  response:
                    type: object
                    properties:
                      _id:
                        type: string
                      status:
                        type: string
                        enum:
                          - pending
                          - processed
                          - spam
                          - deleted
                      flaggedAsSpam:
                        type: boolean
        "400":
          description: Invalid status
          content:
            application/json:
              schema:
                description: Invalid status
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
        "404":
          description: Response not found
          content:
            application/json:
              schema:
                description: Response not found
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/forms/{id}/responses/{responseId}/spam:
    post:
      tags:
        - forms
      description: Mark a form response as spam
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
          description: Form ID
        - schema:
            type: string
          in: path
          name: responseId
          required: true
          description: Response ID
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Response marked as spam successfully
          content:
            application/json:
              schema:
                description: Response marked as spam successfully
                type: object
                properties:
                  success:
                    type: boolean
                  response:
                    type: object
                    properties:
                      _id:
                        type: string
                      status:
                        type: string
                        enum:
                          - spam
                      flaggedAsSpam:
                        type: boolean
        "404":
          description: Response not found
          content:
            application/json:
              schema:
                description: Response not found
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/feature-flags:
    get:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  flags:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        key:
                          type: string
                        label:
                          type: string
                        description:
                          type: string
                        defaultEnabled:
                          type: boolean
                        notes:
                          type: string
                        createdAt:
                          type: string
                        updatedAt:
                          type: string
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                key:
                  type: string
                  minLength: 1
                label:
                  type: string
                  minLength: 1
                description:
                  type: string
                defaultEnabled:
                  type: boolean
                notes:
                  type: string
              required:
                - key
                - label
        required: true
      responses:
        "201":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  flag:
                    type: object
                    properties:
                      id:
                        type: string
                      key:
                        type: string
                      label:
                        type: string
                      description:
                        type: string
                      defaultEnabled:
                        type: boolean
                      notes:
                        type: string
                      createdAt:
                        type: string
                      updatedAt:
                        type: string
  /api/galleries:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: search
          required: false
        - schema:
            type: string
          in: query
          name: contentId
          required: false
        - schema:
            type: number
          in: query
          name: page
          required: false
        - schema:
            type: number
          in: query
          name: limit
          required: false
      responses:
        "200":
          description: Default Response
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                  minLength: 1
                description:
                  type: string
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      mediaId:
                        type: string
                      title:
                        type: string
                      caption:
                        type: string
                      order:
                        type: number
                    required:
                      - mediaId
                linkedContentIds:
                  type: array
                  items:
                    type: string
                status:
                  type: string
              required:
                - title
        required: true
      responses:
        "200":
          description: Default Response
  /api/galleries/{id}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                title:
                  type: string
                description:
                  type: string
                items:
                  type: array
                  items:
                    type: object
                    properties:
                      mediaId:
                        type: string
                      title:
                        type: string
                      caption:
                        type: string
                      order:
                        type: number
                linkedContentIds:
                  type: array
                  items:
                    type: string
                status:
                  type: string
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/collections:
    get:
      parameters:
        - schema:
            type: string
            enum:
              - active
              - archived
          in: query
          name: status
          required: false
      responses:
        "200":
          description: Default Response
    post:
      responses:
        "200":
          description: Default Response
  /api/collections/{key}:
    put:
      parameters:
        - schema:
            type: string
          in: path
          name: key
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: key
          required: true
      responses:
        "200":
          description: Default Response
  /api/collections/{key}/entries:
    get:
      summary: List collection entries
      tags:
        - collections
      description: Enum fields include dataLabels with locale maps when available.
      parameters:
        - schema:
            type: number
          in: query
          name: page
          required: false
        - schema:
            type: number
          in: query
          name: limit
          required: false
        - schema:
            type: string
            enum:
              - draft
              - published
              - archived
          in: query
          name: status
          required: false
        - schema:
            type: string
          in: query
          name: q
          required: false
        - schema:
            type: string
          in: query
          name: sort
          required: false
        - schema:
            anyOf:
              - type: string
              - type: object
                additionalProperties: true
          in: query
          name: filter
          required: false
        - schema:
            type: string
          in: path
          name: key
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                      properties:
                        _id:
                          type: string
                        collectionKey:
                          type: string
                        slug:
                          type: string
                        status:
                          type: string
                          enum:
                            - draft
                            - published
                            - archived
                        data:
                          type: object
                          additionalProperties: true
                        dataLabels:
                          type: object
                          description: Enum labels per field key. Values are locale maps or arrays for
                            multi-select enums.
                          additionalProperties: true
                        relations:
                          type: object
                          additionalProperties: true
                        indexed:
                          type: object
                          additionalProperties: true
                        createdAt:
                          type: string
                          format: date-time
                        updatedAt:
                          type: string
                          format: date-time
                  pagination:
                    type: object
                    properties:
                      page:
                        type: number
                      limit:
                        type: number
                      total:
                        type: number
                      pages:
                        type: number
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: key
          required: true
      responses:
        "200":
          description: Default Response
  /api/collections/{key}/entries/{id}:
    put:
      parameters:
        - schema:
            type: string
          in: path
          name: key
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: key
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/mail/test:
    get:
      responses:
        "200":
          description: Default Response
  /api/placements:
    get:
      responses:
        "200":
          description: Default Response
    post:
      responses:
        "200":
          description: Default Response
  /api/placements/{id}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    put:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/archive:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/duplicate:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/experiences:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/experiences/{expId}:
    put:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
        - schema:
            type: string
          in: path
          name: expId
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
        - schema:
            type: string
          in: path
          name: expId
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/debug-decision:
    post:
      summary: Explain an admin placement decision
      tags:
        - placements
      description: Evaluates a draft or saved placement against a test context and
        returns eligible/rejected experiences with rejection reasons.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - placement
                - context
              properties:
                placement:
                  type: object
                  additionalProperties: true
                context:
                  type: object
                  required:
                    - path
                    - sessionId
                  additionalProperties: true
                  properties:
                    path:
                      type: string
                    locale:
                      type: string
                    device:
                      type: string
                      enum:
                        - mobile
                        - tablet
                        - desktop
                    browser:
                      type: string
                    os:
                      type: string
                    authenticated:
                      type: boolean
                    userRoles:
                      type: array
                      items:
                        type: string
                    userTags:
                      type: array
                      items:
                        type: string
                    featureFlags:
                      type: array
                      items:
                        type: string
                    query:
                      type: object
                      additionalProperties: true
                    cookies:
                      type: object
                      additionalProperties: true
                    referrer:
                      type: string
                    sessionId:
                      type: string
                    userKey:
                      type: string
                    seenCaps:
                      type: object
                      additionalProperties:
                        type: number
        required: true
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        "400":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /api/public/placements/decide:
    post:
      summary: Get a public placement decision
      tags:
        - placements
      description: Returns the eligible experience for a placement slug with
        renderer-ready content, UI, trigger, and tracking context. Use
        X-Tenant-ID for public integrations.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - placement
                - context
              properties:
                placement:
                  type: string
                context:
                  type: object
                  required:
                    - path
                    - sessionId
                  additionalProperties: true
                  properties:
                    path:
                      type: string
                    locale:
                      type: string
                    device:
                      type: string
                      enum:
                        - mobile
                        - tablet
                        - desktop
                    browser:
                      type: string
                    os:
                      type: string
                    authenticated:
                      type: boolean
                    userRoles:
                      type: array
                      items:
                        type: string
                    userTags:
                      type: array
                      items:
                        type: string
                    featureFlags:
                      type: array
                      items:
                        type: string
                    query:
                      type: object
                      additionalProperties: true
                    cookies:
                      type: object
                      additionalProperties: true
                    referrer:
                      type: string
                    sessionId:
                      type: string
                    userKey:
                      type: string
                    seenCaps:
                      type: object
                      additionalProperties:
                        type: number
        required: true
      security:
        - tenantId: []
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
                properties:
                  decisionId:
                    type: string
                  placementId:
                    type: string
                  experienceId:
                    type: string
                  contentType:
                    type: string
                    enum:
                      - content
                      - media
                      - form
                      - html
                      - component
                      - external
                      - text
                      - image
                      - video
                  payload:
                    type: object
                    additionalProperties: true
                  content:
                    type: object
                    additionalProperties: true
                    description: Renderer-ready content. Form placements include fields, settings,
                      formId, form, and submitEndpoint.
                  ui:
                    type: object
                    additionalProperties: true
                  trigger:
                    type: object
                    additionalProperties: true
                  placement:
                    type: object
                    additionalProperties: true
                  experience:
                    type: object
                    additionalProperties: true
                  tracking:
                    type: object
                    additionalProperties: true
                  trackingContext:
                    type: object
                    additionalProperties: true
                  meta:
                    type: object
                    additionalProperties: true
        "400":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
        "404":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /api/public/placements/{slug}:
    get:
      summary: Get public placement details
      tags:
        - placements
      description: Returns active placement metadata and active experiences for custom
        UI builders or presentation layers. Form experiences include the public
        form definition and submit endpoint.
      parameters:
        - schema:
            type: string
          in: path
          name: slug
          required: true
      security:
        - tenantId: []
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  placement:
                    type: object
                    additionalProperties: true
                    properties:
                      id:
                        type: string
                      slug:
                        type: string
                      name: {}
                      description:
                        type: string
                      category:
                        type: string
                      status:
                        type: string
                      defaultRules:
                        type: object
                        additionalProperties: true
                      settings:
                        type: object
                        additionalProperties: true
                      tags:
                        type: array
                        items:
                          type: string
                      experiences:
                        type: array
                        items:
                          type: object
                          additionalProperties: true
                          properties:
                            id:
                              type: string
                            name:
                              type: string
                            status:
                              type: string
                            contentType:
                              type: string
                            payload:
                              type: object
                              additionalProperties: true
                            content:
                              type: object
                              additionalProperties: true
                            ui:
                              type: object
                              additionalProperties: true
                            trigger:
                              type: object
                              additionalProperties: true
                            rules:
                              type: object
                              additionalProperties: true
                            conversions:
                              type: object
                              additionalProperties: true
        "404":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /api/public/placements/decide-batch:
    post:
      summary: Get public placement decisions in batch
      tags:
        - placements
      description: Returns a slug-keyed object with decisions for eligible placements.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - placements
                - context
              properties:
                placements:
                  type: array
                  minItems: 1
                  items:
                    type: string
                context:
                  type: object
                  required:
                    - path
                    - sessionId
                  additionalProperties: true
                  properties:
                    path:
                      type: string
                    locale:
                      type: string
                    device:
                      type: string
                      enum:
                        - mobile
                        - tablet
                        - desktop
                    browser:
                      type: string
                    os:
                      type: string
                    authenticated:
                      type: boolean
                    userRoles:
                      type: array
                      items:
                        type: string
                    userTags:
                      type: array
                      items:
                        type: string
                    featureFlags:
                      type: array
                      items:
                        type: string
                    query:
                      type: object
                      additionalProperties: true
                    cookies:
                      type: object
                      additionalProperties: true
                    referrer:
                      type: string
                    sessionId:
                      type: string
                    userKey:
                      type: string
                    seenCaps:
                      type: object
                      additionalProperties:
                        type: number
        required: true
      security:
        - tenantId: []
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: object
                  additionalProperties: true
                  properties:
                    decisionId:
                      type: string
                    placementId:
                      type: string
                    experienceId:
                      type: string
                    contentType:
                      type: string
                      enum:
                        - content
                        - media
                        - form
                        - html
                        - component
                        - external
                        - text
                        - image
                        - video
                    payload:
                      type: object
                      additionalProperties: true
                    content:
                      type: object
                      additionalProperties: true
                      description: Renderer-ready content. Form placements include fields, settings,
                        formId, form, and submitEndpoint.
                    ui:
                      type: object
                      additionalProperties: true
                    trigger:
                      type: object
                      additionalProperties: true
                    placement:
                      type: object
                      additionalProperties: true
                    experience:
                      type: object
                      additionalProperties: true
                    tracking:
                      type: object
                      additionalProperties: true
                    trackingContext:
                      type: object
                      additionalProperties: true
                    meta:
                      type: object
                      additionalProperties: true
        "400":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /api/public/placements/event:
    post:
      summary: Track a public placement event
      tags:
        - placements
      description: Tracks impression, view, click, close, dismiss, submit, conversion,
        or error events for placement analytics.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - placementId
                - experienceId
                - type
                - sessionId
                - path
              additionalProperties: true
              properties:
                placementId:
                  type: string
                experienceId:
                  type: string
                type:
                  type: string
                  enum:
                    - impression
                    - view
                    - click
                    - close
                    - dismiss
                    - submit
                    - conversion
                    - error
                sessionId:
                  type: string
                trackingId:
                  type: string
                userKey:
                  type: string
                path:
                  type: string
                referrer:
                  type: string
                locale:
                  type: string
                device:
                  type: string
                  enum:
                    - mobile
                    - tablet
                    - desktop
                    - unknown
                conversionGoal:
                  type: string
                conversionValue:
                  type: number
                formId:
                  type: string
                formData:
                  type: object
                  additionalProperties: true
                metadata:
                  type: object
                  additionalProperties: true
        required: true
      security:
        - tenantId: []
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
        "400":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /api/public/placements/events/batch:
    post:
      summary: Track public placement events in batch
      tags:
        - placements
      description: Accepts queued placement analytics events from SDK/offline clients.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - events
              properties:
                events:
                  type: array
                  minItems: 1
                  maxItems: 100
                  items:
                    type: object
                    additionalProperties: true
        required: true
      security:
        - tenantId: []
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                  count:
                    type: number
        "400":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                additionalProperties: true
  /api/placements/{id}/stats/totals:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/stats:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/experiences/{expId}/funnel:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
        - schema:
            type: string
          in: path
          name: expId
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/ab-test:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/stats/devices:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/stats/browsers:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/stats/top-pages:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/{id}/stats/realtime:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/placements/journey:
    get:
      responses:
        "200":
          description: Default Response
  /api/menus:
    get:
      responses:
        "200":
          description: Default Response
    post:
      responses:
        "200":
          description: Default Response
  /api/menus/{id}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    put:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/menus/{id}/tree:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/menus/{id}/duplicate:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/menus/{id}/items:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/menus/{id}/items/{itemId}:
    put:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
        - schema:
            type: string
          in: path
          name: itemId
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
        - schema:
            type: string
          in: path
          name: itemId
          required: true
      responses:
        "200":
          description: Default Response
  /api/menus/{id}/reorder:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/menus/{id}/items/{itemId}/move:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
        - schema:
            type: string
          in: path
          name: itemId
          required: true
      responses:
        "200":
          description: Default Response
  /api/menus/stats:
    get:
      responses:
        "200":
          description: Default Response
  /api/public/menus/location/{location}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: location
          required: true
      responses:
        "200":
          description: Default Response
  /api/public/menus/slug/{slug}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: slug
          required: true
      responses:
        "200":
          description: Default Response
  /api/roles:
    get:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  roles:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        key:
                          type: string
                        name:
                          type: string
                        description:
                          type: string
                        level:
                          type: number
                        permissions:
                          type: array
                          items:
                            type: string
                        tenantId:
                          type: string
                          nullable: true
                        isDefault:
                          type: boolean
                        isSystem:
                          type: boolean
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                key:
                  type: string
                level:
                  type: number
                permissions:
                  type: array
                  items:
                    type: string
                baseRoleKey:
                  type: string
              required:
                - name
        required: true
      responses:
        "201":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  role:
                    type: object
                    properties:
                      id:
                        type: string
                      key:
                        type: string
                      name:
                        type: string
                      description:
                        type: string
                      level:
                        type: number
                      permissions:
                        type: array
                        items:
                          type: string
                      tenantId:
                        type: string
                        nullable: true
                      isDefault:
                        type: boolean
                      isSystem:
                        type: boolean
  /api/roles/{id}:
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                level:
                  type: number
                permissions:
                  type: array
                  items:
                    type: string
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
  /api/public/collections/{key}:
    get:
      summary: List public collection entries
      tags:
        - collections
      description: Enum fields include dataLabels with locale maps when available.
      parameters:
        - schema:
            type: string
          in: path
          name: key
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      additionalProperties: true
                      properties:
                        id:
                          type: string
                        collectionKey:
                          type: string
                        slug:
                          type: string
                        status:
                          type: string
                          enum:
                            - draft
                            - published
                            - archived
                        data:
                          type: object
                          additionalProperties: true
                        dataLabels:
                          type: object
                          description: Enum labels per field key. Values are locale maps or arrays for
                            multi-select enums.
                          additionalProperties: true
                        relations:
                          type: object
                          additionalProperties: true
                        indexed:
                          type: object
                          additionalProperties: true
                        createdAt:
                          type: string
                          format: date-time
                        updatedAt:
                          type: string
                          format: date-time
                  pagination:
                    type: object
                    properties:
                      page:
                        type: number
                      limit:
                        type: number
                      total:
                        type: number
                      pages:
                        type: number
  /api/public/collections/{key}/{slug}:
    get:
      summary: Get public collection entry by slug
      tags:
        - collections
      description: Enum fields include dataLabels with locale maps when available.
      parameters:
        - schema:
            type: string
          in: path
          name: key
          required: true
        - schema:
            type: string
          in: path
          name: slug
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  entry:
                    type: object
                    additionalProperties: true
                    properties:
                      id:
                        type: string
                      collectionKey:
                        type: string
                      slug:
                        type: string
                      status:
                        type: string
                        enum:
                          - draft
                          - published
                          - archived
                      data:
                        type: object
                        additionalProperties: true
                      dataLabels:
                        type: object
                        description: Enum labels per field key. Values are locale maps or arrays for
                          multi-select enums.
                        additionalProperties: true
                      relations:
                        type: object
                        additionalProperties: true
                      indexed:
                        type: object
                        additionalProperties: true
                      createdAt:
                        type: string
                        format: date-time
                      updatedAt:
                        type: string
                        format: date-time
  /api/public/queries/run:
    post:
      summary: Run public collection query
      tags:
        - collections
      description: Executes a DSL query. Enum labels are included in dataLabels when
        select is omitted.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - collection
              properties:
                collection:
                  type: string
                  description: Collection key to query
                select:
                  type: array
                  description: Optional field selection list (e.g. data.fullname, slug)
                  items:
                    type: string
                where:
                  type: array
                  description: Filter clauses as [field, operator, value]
                  items:
                    type: array
                    minItems: 3
                    maxItems: 3
                orderBy:
                  type: array
                  description: Sort clauses as [field, direction]
                  items:
                    type: array
                    minItems: 2
                    maxItems: 2
                limit:
                  type: number
                offset:
                  type: number
                page:
                  type: number
                includeRelations:
                  type: array
                  items:
                    type: string
                    enum:
                      - media
                      - contents
                      - refs
              additionalProperties: true
        required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      description: Query result row. When select is omitted, this matches
                        publicEntrySchema and includes dataLabels.
                      additionalProperties: true
                      properties:
                        dataLabels:
                          type: object
                          description: Enum labels per field key. Values are locale maps or arrays for
                            multi-select enums.
                          additionalProperties: true
                  pagination:
                    type: object
                    properties:
                      total:
                        type: number
                      limit:
                        type: number
                      offset:
                        type: number
                      page:
                        type: number
                      pages:
                        type: number
  /api/public/forms/{slug}:
    get:
      summary: Get public form by slug
      tags:
        - forms
      description: Get a published form definition by slug. Provide either
        Authorization header with API token (preferred) or X-Tenant-ID header.
      parameters:
        - schema:
            type: string
          in: path
          name: slug
          required: true
          description: Form slug (URL-friendly identifier)
      security:
        - apiToken: []
        - {}
      responses:
        "200":
          description: Form definition with all field properties for rendering
          content:
            application/json:
              schema:
                description: Form definition with all field properties for rendering
                type: object
                properties:
                  form:
                    type: object
                    properties:
                      id:
                        type: string
                        description: Form ID
                      title:
                        type: object
                        description: Multilingual title
                      description:
                        type: object
                        description: Multilingual description
                      slug:
                        type: string
                        description: Form slug
                      fields:
                        type: array
                        description: Form fields with complete rendering information
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              description: Field unique ID
                            type:
                              type: string
                              description: Field type (text, email, select, etc.)
                            name:
                              type: string
                              description: Field name for form submission
                            label:
                              type: object
                              description: Multilingual label
                            placeholder:
                              type: object
                              description: Multilingual placeholder
                            helpText:
                              type: object
                              description: Multilingual help text
                            required:
                              type: boolean
                              description: Is field required
                            validation:
                              type: object
                              description: Validation rules (min, max, pattern, etc.)
                            options:
                              type: array
                              description: Options for select/radio/checkbox fields
                            conditionalLogic:
                              type: object
                              description: Conditional display logic
                            defaultValue:
                              description: Default value
                            order:
                              type: number
                              description: Display order
                            width:
                              type: string
                              description: Field width (full, half, third, quarter)
                            className:
                              type: string
                              description: Custom CSS class
                            readOnly:
                              type: boolean
                              description: Is field read-only
                            disabled:
                              type: boolean
                              description: Is field disabled
                            hidden:
                              type: boolean
                              description: Is field hidden
                      settings:
                        type: object
                        properties:
                          submitButtonText:
                            type: object
                            description: Multilingual submit button text
                          successMessage:
                            type: object
                            description: Multilingual success message
                          redirectUrl:
                            type: string
                            description: Redirect URL after submission
                          enableCaptcha:
                            type: boolean
                            description: Is CAPTCHA enabled
                          requireAuth:
                            type: boolean
                            description: Does form require authentication
        "400":
          description: Tenant ID or API key required
          content:
            application/json:
              schema:
                description: Tenant ID or API key required
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
        "404":
          description: Form not found or not published
          content:
            application/json:
              schema:
                description: Form not found or not published
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/public/forms/{formId}/submit:
    post:
      summary: Submit a public form
      tags:
        - forms
      description: Submit a form response using API token authentication. Provide API
        token in Authorization header as "Bearer ctx_YOUR_KEY". Rate limited to
        10 submissions per minute per IP.
      requestBody:
        content:
          application/json:
            schema:
              type: object
              required:
                - data
              properties:
                data:
                  type: object
                  description: Form field data as key-value pairs (field names should match form
                    definition)
                  additionalProperties: true
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: formId
          required: true
          description: Form ID (ObjectId)
      security:
        - apiToken: []
      responses:
        "201":
          description: Form submitted successfully
          content:
            application/json:
              schema:
                description: Form submitted successfully
                type: object
                properties:
                  success:
                    type: boolean
                  message:
                    type: object
                    description: Success message in multiple languages
                  responseId:
                    type: string
                    description: Created response ID
        "400":
          description: Validation error or invalid data
          content:
            application/json:
              schema:
                description: Validation error or invalid data
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
        "401":
          description: API key missing or invalid
          content:
            application/json:
              schema:
                description: API key missing or invalid
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
        "404":
          description: Form not found or not published
          content:
            application/json:
              schema:
                description: Form not found or not published
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
        "429":
          description: Rate limit exceeded (10 submissions per minute)
          content:
            application/json:
              schema:
                description: Rate limit exceeded (10 submissions per minute)
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/dashboard/summary:
    get:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  totals:
                    type: object
                    properties:
                      users:
                        type: number
                      contents:
                        type: number
                      media:
                        type: object
                        properties:
                          count:
                            type: number
                          totalSize:
                            type: number
  /api/dashboard/activities:
    get:
      parameters:
        - schema:
            type: string
          in: query
          name: type
          required: false
        - schema:
            type: string
            enum:
              - tenant
              - self
          in: query
          name: scope
          required: false
        - schema:
            type: number
            minimum: 1
            maximum: 50
          in: query
          name: limit
          required: false
        - schema:
            type: number
            minimum: 0
          in: query
          name: offset
          required: false
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  items:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        entityId:
                          type: string
                        entityType:
                          type: string
                        action:
                          type: string
                        title:
                          type: string
                        timestamp:
                          type: string
                        actorId:
                          type:
                            - "null"
                            - string
                        actor:
                          anyOf:
                            - type: "null"
                            - type: object
                              properties:
                                id:
                                  type: string
                                name:
                                  type: string
                                email:
                                  type:
                                    - string
                                    - "null"
                        metadata:
                          type: object
                  pagination:
                    type: object
                    properties:
                      limit:
                        type: number
                      offset:
                        type: number
                      hasMore:
                        type: boolean
                  availableTypes:
                    type: array
                    items:
                      type: string
  /api/dashboard/api-stats:
    get:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  fourHour:
                    type: number
                  daily:
                    type: number
                  today:
                    type: number
                  weekly:
                    type: number
                  monthly:
                    type: number
                  enabled:
                    type: boolean
  /api/dashboard/api-stats-debug:
    get:
      responses:
        "200":
          description: Default Response
  /api/api-usage-sync/trigger:
    post:
      parameters:
        - schema:
            type: boolean
          in: query
          name: includeCurrent
          required: false
        - schema:
            type: boolean
          in: query
          name: force
          required: false
      responses:
        "200":
          description: Default Response
  /api/api-usage-sync/fourhour:
    post:
      responses:
        "200":
          description: Default Response
  /api/api-usage-sync/halfday:
    post:
      responses:
        "200":
          description: Default Response
  /api/api-usage-sync/daily:
    post:
      responses:
        "200":
          description: Default Response
  /api/api-usage-sync/weekly:
    post:
      responses:
        "200":
          description: Default Response
  /api/api-usage-sync/monthly:
    post:
      responses:
        "200":
          description: Default Response
  /api/api-usage-sync/status:
    get:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  provider:
                    type: string
                  usageRedisEnabled:
                    type: boolean
                  period:
                    type: string
  /api/subscription-plans:
    get:
      responses:
        "200":
          description: Default Response
  /api/subscription-plans/{slug}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: slug
          required: true
      responses:
        "200":
          description: Default Response
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                description:
                  type: string
                price:
                  type: number
                userLimit:
                  type:
                    - number
                    - "null"
                ownerLimit:
                  type:
                    - number
                    - "null"
                storageLimit:
                  type: number
                monthlyRequestLimit:
                  type: number
                features:
                  type: array
                  items:
                    type: string
                    pattern: ^[a-z][a-z0-9]*(?:[.-][a-z0-9]+)*$
                  uniqueItems: true
                pricePerGBStorage:
                  type: number
                pricePerThousandRequests:
                  type: number
                isActive:
                  type: boolean
                sortOrder:
                  type: number
      parameters:
        - schema:
            type: string
          in: path
          name: slug
          required: true
      responses:
        "200":
          description: Default Response
  /api/tenants/{tenantId}/subscription:
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - customLimits
              properties:
                customLimits:
                  type: object
                  properties:
                    userLimit:
                      type:
                        - number
                        - "null"
                    ownerLimit:
                      type:
                        - number
                        - "null"
                    storageLimit:
                      type:
                        - number
                        - "null"
                    monthlyRequestLimit:
                      type:
                        - number
                        - "null"
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
  /api/tenants/{tenantId}/limits:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
  /api/tenants/current/limits:
    get:
      responses:
        "200":
          description: Default Response
  /api/billing/overview:
    get:
      responses:
        "200":
          description: Default Response
  /api/billing/checkout:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              anyOf:
                - required:
                    - priceId
                - required:
                    - priceKey
              properties:
                priceId:
                  type: string
                  maxLength: 100
                priceKey:
                  type: string
                  maxLength: 100
      responses:
        "200":
          description: Default Response
  /api/billing/profile:
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required:
                - billingEmail
                - legalName
                - profileType
                - contactFirstName
                - contactLastName
                - phone
                - country
                - address
                - declarationAccepted
                - serviceAgreementAccepted
              properties:
                billingEmail:
                  type: string
                  format: email
                  minLength: 3
                  maxLength: 254
                legalName:
                  type: string
                  minLength: 2
                  maxLength: 200
                profileType:
                  type: string
                  enum:
                    - individual
                    - business
                contactFirstName:
                  type: string
                  minLength: 1
                  maxLength: 100
                contactLastName:
                  type: string
                  minLength: 1
                  maxLength: 100
                phone:
                  type: string
                  minLength: 8
                  maxLength: 30
                country:
                  type: string
                  minLength: 2
                  maxLength: 2
                  pattern: ^[A-Za-z]{2}$
                taxId:
                  type: string
                  maxLength: 32
                taxOffice:
                  type: string
                  maxLength: 120
                declarationAccepted:
                  type: boolean
                  enum:
                    - true
                serviceAgreementAccepted:
                  type: boolean
                  enum:
                    - true
                address:
                  type: object
                  additionalProperties: false
                  required:
                    - line1
                    - city
                    - postalCode
                  properties:
                    line1:
                      type: string
                      minLength: 3
                      maxLength: 250
                    line2:
                      type: string
                      maxLength: 250
                    city:
                      type: string
                      minLength: 1
                      maxLength: 100
                    district:
                      type: string
                      maxLength: 100
                    region:
                      type: string
                      maxLength: 100
                    postalCode:
                      type: string
                      minLength: 2
                      maxLength: 12
        required: true
      responses:
        "200":
          description: Default Response
  /api/billing/portal:
    post:
      responses:
        "200":
          description: Default Response
  /api/billing/invoices/{invoiceId}/document:
    get:
      parameters:
        - schema:
            type: string
            pattern: ^[a-fA-F0-9]{24}$
          in: path
          name: invoiceId
          required: true
      responses:
        "200":
          description: Default Response
  /api/billing/webhooks/paddle:
    post:
      responses:
        "200":
          description: Default Response
  /api/billing/webhooks/iyzico:
    post:
      responses:
        "200":
          description: Default Response
  /api/billing/callbacks/iyzico:
    post:
      responses:
        "200":
          description: Default Response
  /api/billing/callbacks/iyzico/card-update:
    post:
      responses:
        "200":
          description: Default Response
    get:
      responses:
        "200":
          description: Default Response
  /api/documentation:
    get:
      summary: Get developer documentation (markdown)
      tags:
        - documentation
      description: Returns the complete developer documentation in markdown format
      responses:
        "200":
          description: Markdown content
          content:
            application/json:
              schema:
                type: string
                description: Markdown content
        "404":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/documentation/html:
    get:
      summary: Get developer documentation (HTML)
      tags:
        - documentation
      description: Returns the complete developer documentation rendered as HTML
      responses:
        "200":
          description: HTML content
          content:
            application/json:
              schema:
                type: string
                description: HTML content
        "404":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
                  message:
                    type: string
  /api/documentation/json:
    get:
      summary: Get documentation metadata
      tags:
        - documentation
      description: Returns metadata about the developer documentation
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  title:
                    type: string
                  version:
                    type: string
                  lastUpdated:
                    type: string
                  path:
                    type: string
                  size:
                    type: number
                  available:
                    type: boolean
  /api/api-tokens:
    get:
      tags:
        - apiTokens
      description: List all API tokens for the current tenant (Owner only)
      security:
        - bearerAuth: []
      responses:
        "200":
          description: List of API tokens
          content:
            application/json:
              schema:
                description: List of API tokens
                type: object
                properties:
                  tokens:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        name:
                          type: string
                        role:
                          type: string
                          description: Role-based permissions
                        scopes:
                          type: array
                          items:
                            type: string
                        expiresAt:
                          type: string
                          format: date-time
                          nullable: true
                        lastUsedAt:
                          type: string
                          format: date-time
                          nullable: true
                        createdAt:
                          type: string
                          format: date-time
                        createdBy:
                          type: object
                          nullable: true
                          properties:
                            id:
                              type: string
                            name:
                              type: string
                            email:
                              type: string
    post:
      tags:
        - apiTokens
      description: Create a new API token for Content-as-a-Service access (Owner
        only). Token is returned only once!
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                  description: Human-readable name for the token
                role:
                  type: string
                  enum:
                    - viewer
                    - author
                    - editor
                    - admin
                    - owner
                  description: Role-based permissions for this token
                  default: viewer
                scopes:
                  type: array
                  items:
                    type: string
                    enum:
                      - read
                      - write
                      - delete
                  description: Permissions for this token
                  default:
                    - read
                expiresInDays:
                  type: number
                  minimum: 0
                  description: Token expiration in days (0 = unlimited)
              required:
                - name
        required: true
      security:
        - bearerAuth: []
      responses:
        "201":
          description: Token created successfully. Save the token - it cannot be retrieved
            again!
          content:
            application/json:
              schema:
                description: Token created successfully. Save the token - it cannot be retrieved
                  again!
                type: object
                properties:
                  token:
                    type: object
                    properties:
                      id:
                        type: string
                      token:
                        type: string
                        description: The actual token starting with ctx_ - save this securely!
                      name:
                        type: string
                      role:
                        type: string
                        description: Role-based permissions for this token
                      scopes:
                        type: array
                        items:
                          type: string
                      expiresAt:
                        type: string
                        format: date-time
                        nullable: true
                      createdAt:
                        type: string
                        format: date-time
                  warning:
                    type: string
                    description: Security warning about token visibility
  /api/api-tokens/{tokenId}:
    delete:
      tags:
        - apiTokens
      description: Delete an API token (Owner only)
      parameters:
        - schema:
            type: string
          in: path
          name: tokenId
          required: true
          description: Token ID to delete
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Token deleted successfully
          content:
            application/json:
              schema:
                description: Token deleted successfully
                type: object
                properties:
                  message:
                    type: string
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  minLength: 1
                scopes:
                  type: array
                  items:
                    type: string
      parameters:
        - schema:
            type: string
          in: path
          name: tokenId
          required: true
      responses:
        "200":
          description: Default Response
  /api/admin/domain-event-types:
    get:
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  types:
                    type: array
                    items:
                      type: string
  /api/admin/tenants/{tenantId}/webhooks:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  webhooks:
                    type: array
                    items:
                      type: object
                      properties:
                        id:
                          type: string
                        tenantId:
                          type: string
                        url:
                          type: string
                        isActive:
                          type: boolean
                        events:
                          type: array
                          items:
                            type: string
                        createdAt:
                          type: string
                          nullable: true
                        updatedAt:
                          type: string
                          nullable: true
                        hasSecret:
                          type: boolean
                  availableEventTypes:
                    type: array
                    items:
                      type: string
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                isActive:
                  type: boolean
                events:
                  type: array
                  items:
                    type: string
                secret:
                  type: string
              required:
                - url
        required: true
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
      responses:
        "201":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  webhook:
                    type: object
                    properties:
                      id:
                        type: string
                      tenantId:
                        type: string
                      url:
                        type: string
                      isActive:
                        type: boolean
                      events:
                        type: array
                        items:
                          type: string
                      createdAt:
                        type: string
                        nullable: true
                      updatedAt:
                        type: string
                        nullable: true
                      hasSecret:
                        type: boolean
                  secret:
                    type: string
  /api/admin/tenants/{tenantId}/webhooks/queue:
    get:
      parameters:
        - schema:
            type: number
            minimum: 1
            maximum: 100
          in: query
          name: limit
          required: false
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  domainEvents:
                    type: object
                    properties:
                      totalPending:
                        type: number
                      items:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              nullable: true
                            type:
                              type: string
                            status:
                              type: string
                            occurredAt:
                              type: string
                              nullable: true
                            createdAt:
                              type: string
                              nullable: true
                            lastError:
                              type: string
                              nullable: true
                            retryCount:
                              type: number
                  outbox:
                    type: object
                    properties:
                      totalPending:
                        type: number
                      totalFailed:
                        type: number
                      pendingItems:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              nullable: true
                            eventId:
                              type: string
                              nullable: true
                            type:
                              type: string
                            status:
                              type: string
                            createdAt:
                              type: string
                              nullable: true
                            updatedAt:
                              type: string
                              nullable: true
                            lastError:
                              type: string
                              nullable: true
                            retryCount:
                              type: number
                      failedItems:
                        type: array
                        items:
                          type: object
                          properties:
                            id:
                              type: string
                              nullable: true
                            eventId:
                              type: string
                              nullable: true
                            type:
                              type: string
                            status:
                              type: string
                            createdAt:
                              type: string
                              nullable: true
                            updatedAt:
                              type: string
                              nullable: true
                            lastError:
                              type: string
                              nullable: true
                            retryCount:
                              type: number
  /api/admin/tenants/{tenantId}/webhooks/{id}:
    put:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                url:
                  type: string
                isActive:
                  type: boolean
                events:
                  type: array
                  items:
                    type: string
              additionalProperties: false
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  webhook:
                    type: object
                    properties:
                      id:
                        type: string
                      tenantId:
                        type: string
                      url:
                        type: string
                      isActive:
                        type: boolean
                      events:
                        type: array
                        items:
                          type: string
                      createdAt:
                        type: string
                        nullable: true
                      updatedAt:
                        type: string
                        nullable: true
                      hasSecret:
                        type: boolean
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
  /api/admin/tenants/{tenantId}/webhooks/{id}/rotate-secret:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  secret:
                    type: string
                  webhook:
                    type: object
                    properties:
                      id:
                        type: string
                      tenantId:
                        type: string
                      url:
                        type: string
                      isActive:
                        type: boolean
                      events:
                        type: array
                        items:
                          type: string
                      createdAt:
                        type: string
                        nullable: true
                      updatedAt:
                        type: string
                        nullable: true
                      hasSecret:
                        type: boolean
  /api/admin/tenants/{tenantId}/webhooks/trigger:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                domainEventLimit:
                  type: number
                  minimum: 1
                  maximum: 500
                webhookLimit:
                  type: number
                  minimum: 1
                  maximum: 500
                maxRetryAttempts:
                  type: number
                  minimum: 1
                  maximum: 25
                retryBackoffMs:
                  type: number
                  minimum: 0
                  maximum: 600000
              additionalProperties: false
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  result:
                    type: object
                    properties:
                      eventsResult:
                        type: object
                      retryResult:
                        type: object
                      dispatchResult:
                        type: object
  /api/admin/tenants/{tenantId}/webhooks/{id}/test:
    post:
      requestBody:
        content:
          application/json:
            schema:
              type: object
              properties:
                payload:
                  type: object
                  additionalProperties: true
              additionalProperties: false
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  status:
                    type: number
  /api/admin/tenants/{tenantId}/webhooks/queue/retry-all:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  matched:
                    type: number
                  retried:
                    type: number
  /api/admin/tenants/{tenantId}/webhooks/queue/failed:
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  deleted:
                    type: number
  /api/admin/tenants/{tenantId}/webhooks/{id}/queue/retry:
    post:
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  matched:
                    type: number
                  retried:
                    type: number
  /api/admin/tenants/{tenantId}/webhooks/{id}/queue/failed:
    delete:
      parameters:
        - schema:
            type: string
          in: path
          name: tenantId
          required: true
        - schema:
            type: string
          in: path
          name: id
          required: true
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  deleted:
                    type: number
  /api/cron/webhooks:
    post:
      summary: Run webhook cron job
      tags:
        - cron
      description: Trigger webhook processing, scheduled content publishing, and
        cleanup for all tenants (requires CRON_SECRET_TOKEN)
      parameters:
        - schema:
            type: string
          in: query
          name: tenant
          required: false
          description: "Optional: process only this tenant (ID or slug)"
        - schema:
            type: string
          in: header
          name: x-cron-secret
          required: true
          description: Secret token from CRON_SECRET_TOKEN env variable
      responses:
        "200":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok:
                    type: boolean
                  aggregate:
                    type: object
                    properties:
                      tenantsProcessed:
                        type: number
                      scheduledMatched:
                        type: number
                      scheduledPublished:
                        type: number
                      eventsProcessed:
                        type: number
                      webhooksDispatched:
                        type: number
                      retryRequeued:
                        type: number
                      cleanupDeleted:
                        type: number
                  summaries:
                    type: array
                    items:
                      type: object
                      properties:
                        tenantId:
                          type: string
                        slug:
                          type: string
                        scheduled:
                          type: object
                        pipeline:
                          type: object
                        cleanup:
                          type: object
        "401":
          description: Default Response
          content:
            application/json:
              schema:
                type: object
                properties:
                  error:
                    type: string
  /api/plugins/semantic-search/policy:
    get:
      responses:
        "200":
          description: Default Response
    put:
      responses:
        "200":
          description: Default Response
  /api/plugins/semantic-search/query:
    post:
      responses:
        "200":
          description: Default Response
  /api/plugins/semantic-search/content-suggestions:
    post:
      responses:
        "200":
          description: Default Response
  /api/plugins/semantic-search/related/{contentId}:
    get:
      parameters:
        - schema:
            type: string
          in: path
          name: contentId
          required: true
      responses:
        "200":
          description: Default Response
    put:
      parameters:
        - schema:
            type: string
          in: path
          name: contentId
          required: true
      responses:
        "200":
          description: Default Response
  /api/plugins/tenant-backup/plan:
    get:
      responses:
        "200":
          description: Default Response
    put:
      responses:
        "200":
          description: Default Response
  /api/plugins/tenant-backup/test-connection:
    post:
      responses:
        "200":
          description: Default Response
  /api/plugins/tenant-backup/runs/latest:
    get:
      responses:
        "200":
          description: Default Response
  /api/plugins/tenant-backup/runs:
    get:
      responses:
        "200":
          description: Default Response
    post:
      responses:
        "200":
          description: Default Response
  /api/plugins/tenant-backup/internal/run-due:
    post:
      responses:
        "200":
          description: Default Response
  /health:
    get:
      responses:
        "200":
          description: Default Response
  /ready:
    get:
      responses:
        "200":
          description: Default Response
servers:
  - url: https://api.ctxhub.net
    description: API Server
tags:
  - name: auth
    description: Authentication endpoints
  - name: users
    description: User management
  - name: tenants
    description: Tenant management
  - name: apiTokens
    description: API Token management for Content-as-a-Service
  - name: content
    description: Content management
  - name: media
    description: Media management
  - name: categories
    description: Category management
  - name: tags
    description: Tag management
  - name: collections
    description: Collection management
  - name: galleries
    description: Gallery management
  - name: forms
    description: Form management and form response handling
  - name: menus
    description: Menu management
  - name: placements
    description: Placement management
  - name: mail
    description: Email services
  - name: roles
    description: Role management
  - name: featureFlags
    description: Feature flag management
  - name: subscriptionPlans
    description: Subscription plan management
  - name: dashboard
    description: Dashboard statistics
  - name: activities
    description: Activity logging
  - name: documentation
    description: Developer documentation
