openapi: 3.0.3
info:
  title: Firefly User Management Service API
  version: 1.0.0
  description: 'HTTP API for managing users, teams, roles, and API keys in the Firefly RBAC system.


    This API provides comprehensive role-based access control functionality including:

    - User management and authentication

    - Team organization and membership

    - Role and permission management (scopes are managed as part of roles)

    - API key generation and management

    - Granular scope-based access control through role assignments

    '
servers:
- url: https://api.firefly.ai/v2
  description: Production server
security:
- BearerAuth: []
paths:
  /user-service/users:
    get:
      summary: List users
      description: List and filter users for the specified account
      tags:
      - Users
      security:
      - BearerAuth: []
      parameters:
      - in: query
        name: search
        schema:
          type: string
          maxLength: 255
        description: Search users by name or email using full-text search
        example: john@example.com
      - in: query
        name: email
        schema:
          type: string
          format: email
          maxLength: 255
        description: Filter by exact email address match (returns single user or empty array)
        example: user@example.com
      - in: query
        name: type
        schema:
          type: string
          enum:
          - USER
          - SA
        description: Filter by user type - either regular USER or Service Account (SA)
        example: USER
      - in: query
        name: role_ids
        schema:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 50
        style: form
        explode: false
        description: Filter by role IDs - users must have at least one of these roles
        example:
        - 550e8400-e29b-41d4-a716-446655440000
      - in: query
        name: team_ids
        schema:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 50
        style: form
        explode: false
        description: Filter by team IDs - users must be members of at least one of these teams
        example:
        - 660f9511-f3ac-52e5-b827-557766551111
      - in: query
        name: limit
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 25
        description: Maximum number of users to return
        example: 25
      - in: query
        name: offset
        schema:
          type: integer
          minimum: 0
          default: 0
        description: Number of users to skip
        example: 0
      responses:
        '200':
          description: Array of users matching the search criteria
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserListResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
    post:
      summary: Create a user
      description: Create a new user in the system
      tags:
      - Users
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserCreateRequest'
      responses:
        '201':
          description: Created user
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '409':
          description: User already exists
  /user-service/users/{userId}:
    parameters:
    - in: path
      name: userId
      required: true
      schema:
        type: string
        format: uuid
      description: User ID
    get:
      summary: Get a user
      description: Retrieve details of a specific user
      tags:
      - Users
      security:
      - BearerAuth: []
      responses:
        '200':
          description: User object
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: User not found
    put:
      summary: Update a user
      description: Update an existing user's information
      tags:
      - Users
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UserUpdateRequest'
      responses:
        '200':
          description: Updated user
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: User not found
    delete:
      summary: Delete a user
      description: Delete a user from the system
      tags:
      - Users
      security:
      - BearerAuth: []
      responses:
        '204':
          description: User deleted successfully
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: User not found
  /user-service/team:
    post:
      summary: Create a team
      description: Create a new team
      tags:
      - Teams
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TeamCreateRequest'
      responses:
        '201':
          description: Created team
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TeamResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /user-service/teams:
    get:
      summary: List teams
      description: Retrieve a list of teams for the specified account
      tags:
      - Teams
      security:
      - BearerAuth: []
      parameters:
      - in: query
        name: limit
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 25
        description: Maximum number of teams to return
      - in: query
        name: offset
        schema:
          type: integer
          minimum: 0
          default: 0
        description: Number of teams to skip
      - in: query
        name: search
        schema:
          type: string
          maxLength: 255
        description: Search teams by name (partial match)
      - in: query
        name: role_ids
        schema:
          type: array
          items:
            type: string
            format: uuid
        style: form
        explode: false
        description: Filter teams by role IDs (comma-separated)
      responses:
        '200':
          description: Array of teams
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TeamListResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /user-service/teams/{teamId}:
    parameters:
    - in: path
      name: teamId
      required: true
      schema:
        type: string
        format: uuid
      description: Team ID
    get:
      summary: Get a team
      description: Retrieve details of a specific team
      tags:
      - Teams
      security:
      - BearerAuth: []
      responses:
        '200':
          description: Team object
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TeamResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Team not found
    put:
      summary: Update a team
      description: Update an existing team
      tags:
      - Teams
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/TeamUpdateRequest'
      responses:
        '200':
          description: Updated team
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TeamResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Team not found
    delete:
      summary: Delete a team
      description: Delete a team from the system
      tags:
      - Teams
      security:
      - BearerAuth: []
      responses:
        '204':
          description: Team deleted successfully
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Team not found
  /user-service/api-keys:
    get:
      summary: List API keys
      description: Retrieve a list of API keys for the specified account
      tags:
      - ApiKeys
      security:
      - BearerAuth: []
      parameters:
      - in: query
        name: search
        schema:
          type: string
          maxLength: 255
        description: Search API keys by alias, description, user name, or team name using full-text search
      - in: query
        name: type
        schema:
          type: string
          enum:
          - TEAM
          - USER
          - SA
        description: Filter by API key type
      - in: query
        name: email
        schema:
          type: string
          format: email
        description: Filter by user email (only returns USER type API keys with matching email)
      - in: query
        name: user_id
        schema:
          type: string
          format: uuid
        description: Filter by user ID (returns API keys associated with this user)
      - in: query
        name: team_id
        schema:
          type: string
          format: uuid
        description: Filter by team ID (returns API keys associated with this team)
      - in: query
        name: limit
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 25
        description: Maximum number of API keys to return
      - in: query
        name: offset
        schema:
          type: integer
          minimum: 0
          default: 0
        description: Number of API keys to skip
      responses:
        '200':
          description: Array of API keys
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyListResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
    post:
      summary: Create an API key
      description: Generate a new API key
      tags:
      - ApiKeys
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiKeyCreateRequest'
      responses:
        '201':
          description: Created API key
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyCreateResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /user-service/api-keys/{keyId}:
    parameters:
    - in: path
      name: keyId
      required: true
      schema:
        type: string
        format: uuid
      description: API Key ID
    get:
      summary: Get an API key
      description: Retrieve details of a specific API key
      tags:
      - ApiKeys
      security:
      - BearerAuth: []
      responses:
        '200':
          description: API Key object
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: API key not found
    delete:
      summary: Revoke an API key
      description: Revoke/delete an API key
      tags:
      - ApiKeys
      security:
      - BearerAuth: []
      responses:
        '204':
          description: API key revoked successfully
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: API key not found
  /user-service/api-keys/{keyId}/rotate:
    parameters:
    - in: path
      name: keyId
      required: true
      schema:
        type: string
        format: uuid
      description: API Key ID
    post:
      summary: Rotate an API key
      description: Generate a new secret for an existing API key, invalidating the old secret. Optionally update alias, description, and expiration date.
      tags:
      - ApiKeys
      security:
      - BearerAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ApiKeyRotateRequest'
      responses:
        '200':
          description: API key rotated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiKeyResponse'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: API key not found
  /api-keys/by-key/{key}:
    parameters:
    - in: path
      name: key
      required: true
      schema:
        type: string
      description: The API key string (e.g., INFL_XXXXXXXXXXXXXXXXXX)
    delete:
      summary: Revoke an API key by key string
      description: Revoke/delete an API key using the key string instead of key ID
      tags:
      - ApiKeys
      security:
      - BearerAuth: []
      responses:
        '204':
          description: API key revoked successfully
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: API key not found
  /user-service/roles:
    get:
      summary: List roles
      description: Retrieve a list of roles for the specified account, including both account-specific roles and Firefly-managed (system-wide) roles. Firefly-managed roles have account_id as empty and are marked with fireflyManaged=true. For Firefly-managed roles, attached_users and team_names are filtered to show only those from the requesting account.
      tags:
      - Roles
      security:
      - BearerAuth: []
      parameters:
      - in: query
        name: limit
        schema:
          type: integer
          minimum: 1
          maximum: 100
          default: 25
        description: Maximum number of roles to return
      - in: query
        name: offset
        schema:
          type: integer
          minimum: 0
          default: 0
        description: Number of roles to skip
      - in: query
        name: search
        schema:
          type: string
          maxLength: 255
        description: Search term to filter roles by name or description
      responses:
        '200':
          description: Array of roles
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleListResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
    post:
      summary: Create a role
      description: Create a new role with specified permissions
      tags:
      - Roles
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleCreateRequest'
      responses:
        '201':
          description: Created role
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
  /user-service/roles/{roleId}:
    parameters:
    - in: path
      name: roleId
      required: true
      schema:
        type: string
        format: uuid
      description: Role ID
    put:
      summary: Update a role
      description: Update an existing role's permissions
      tags:
      - Roles
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/RoleUpdateRequest'
      responses:
        '200':
          description: Updated role
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/RoleResponse'
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Role not found
    delete:
      summary: Delete a role
      description: Delete a role from the system
      tags:
      - Roles
      security:
      - BearerAuth: []
      responses:
        '204':
          description: Role deleted successfully
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Role not found
  /scopes:
    get:
      summary: Get all scopes
      description: Retrieve all scopes in a tree format with available filters. This endpoint does not require authentication and returns the complete scope hierarchy.
      tags:
      - Scopes
      security: []
      responses:
        '200':
          description: Tree-structured list of all scopes with their available filters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ScopeTreeResponse'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
  /user-service/teams/{teamId}/members:
    parameters:
    - in: path
      name: teamId
      required: true
      schema:
        type: string
        format: uuid
      description: Team ID
    post:
      summary: Add user to team
      description: Add a single user to the specified team
      tags:
      - Teams
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - user_id
              properties:
                user_id:
                  type: string
                  format: uuid
                  description: User ID to add to the team
      responses:
        '201':
          description: User added to team successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: User added to team successfully
                  user_id:
                    type: string
                    format: uuid
                  team_id:
                    type: string
                    format: uuid
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: User or team not found
        '409':
          description: User already in team
  /user-service/teams/{teamId}/members/bulk:
    parameters:
    - in: path
      name: teamId
      required: true
      schema:
        type: string
        format: uuid
      description: Team ID
    post:
      summary: Add multiple users to team
      description: Add multiple users to the specified team in a single operation
      tags:
      - Teams
      security:
      - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
              - user_ids
              properties:
                user_ids:
                  type: array
                  items:
                    type: string
                    format: uuid
                  description: Array of user IDs to add to the team
                  minItems: 1
                  maxItems: 100
                skip_existing:
                  type: boolean
                  default: true
                  description: Skip users that are already in the team instead of returning error
      responses:
        '201':
          description: Users added to team successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  message:
                    type: string
                    example: Users added to team successfully
                  added_users:
                    type: array
                    items:
                      type: string
                      format: uuid
                    description: User IDs that were successfully added
                  skipped_users:
                    type: array
                    items:
                      type: string
                      format: uuid
                    description: User IDs that were skipped (already in team)
                  failed_users:
                    type: array
                    items:
                      type: object
                      properties:
                        user_id:
                          type: string
                          format: uuid
                        error:
                          type: string
                    description: User IDs that failed to be added with error reasons
        '400':
          description: Bad request
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '401':
          description: Unauthorized
        '403':
          description: Forbidden
        '404':
          description: Team not found
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT
  schemas:
    User:
      type: object
      required:
      - id
      - account_id
      - name
      - created_at
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the user
        account_id:
          type: string
          description: Account identifier this user belongs to
        name:
          type: string
          description: User's full name
        email:
          type: string
          format: email
          nullable: true
          description: User's email address
        description:
          type: string
          nullable: true
          description: User's description or bio
        profile_photo:
          type: string
          format: uri
          nullable: true
          description: URL to user's profile photo
        created_at:
          type: string
          format: date-time
          description: When the user was created
        last_login:
          type: string
          format: date-time
          nullable: true
          description: User's last login time
        email_verified:
          type: boolean
          description: Whether the user's email has been verified
        assigned_role_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of role IDs directly assigned to this user
        team_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of team IDs this user belongs to
        connection:
          type: string
          nullable: true
          description: Connection/authentication provider used by the user
        created_by:
          type: string
          format: uuid
          nullable: true
          description: User ID of the person who created this user
        created_by_name:
          type: string
          nullable: true
          description: Name of the user who created this user
        system_generated:
          type: boolean
          description: Whether this service account was automatically created by the system during migrations or other automated processes
        type:
          type: string
          enum:
          - USER
          - SA
          description: User type - either regular USER or Service Account (SA)
    Team:
      type: object
      required:
      - id
      - account_id
      - name
      - created_at
      - updated_at
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the team
        account_id:
          type: string
          description: Account identifier this team belongs to
        name:
          type: string
          description: Team name
        description:
          type: string
          nullable: true
          description: Team description
        users:
          type: array
          items:
            type: object
            properties:
              id:
                type: string
                format: uuid
                description: User ID
              name:
                type: string
                description: User name
          description: List of users with their IDs and names
        attached_role_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of role IDs assigned to this team
        created_at:
          type: string
          format: date-time
          description: When the team was created
        updated_at:
          type: string
          format: date-time
          description: When the team was last updated
    ApiKey:
      type: object
      required:
      - id
      - account_id
      - type
      - created_at
      - key
      - is_legacy
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the API key
        key:
          type: string
          description: The key identifier (defaults to id for legacy keys, can be updated to any string value)
        is_legacy:
          type: boolean
          description: Whether this is a legacy API key
          default: false
        account_id:
          type: string
          description: Account identifier this API key belongs to
        type:
          type: string
          enum:
          - TEAM
          - USER
          description: Type of API key (scope)
        user_id:
          type: string
          format: uuid
          nullable: true
          description: User ID if this is a user-scoped API key
        user_name:
          type: string
          nullable: true
          description: Name of the user if this is a user-scoped API key
        team_id:
          type: string
          format: uuid
          nullable: true
          description: Team ID if this is a team-scoped API key
        team_name:
          type: string
          nullable: true
          description: Name of the team if this is a team-scoped API key
        alias:
          type: string
          nullable: true
          description: Human-readable alias for the API key
        description:
          type: string
          nullable: true
          description: Description of the API key's purpose
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: When the API key expires
        last_used:
          type: string
          format: date-time
          nullable: true
          description: When the API key was last used for authentication
        created_by:
          type: string
          format: uuid
          nullable: true
          description: User ID of the person who created this API key
        created_by_name:
          type: string
          nullable: true
          description: Name of the user who created this API key
        created_at:
          type: string
          format: date-time
          description: When the API key was created
        updated_at:
          type: string
          format: date-time
          description: When the API key was last updated
    Role:
      type: object
      required:
      - id
      - account_id
      - name
      - scopes
      - created_at
      - updated_at
      - attached_users
      - team_names
      - firefly_managed
      properties:
        id:
          type: string
          format: uuid
          description: Unique identifier for the role
        account_id:
          type: string
          description: Account identifier this role belongs to
        name:
          type: string
          description: Role name
        description:
          type: string
          nullable: true
          description: Role description
        integrationIds:
          type: array
          items:
            type: string
          description: Optional list of integration IDs to restrict role's access to specific integrations
          example:
          - integration-123
          - integration-456
        providers:
          type: array
          items:
            type: string
          description: Optional list of provider types to restrict role's access to specific providers
          example:
          - aws
          - azure
          - gcp
        scopes:
          type: array
          items:
            $ref: '#/components/schemas/RoleScope'
          description: List of scopes/permissions assigned to this role
        attached_users:
          type: array
          items:
            $ref: '#/components/schemas/RoleUser'
          description: Details of users that have this role assigned (name and profile photo). For Firefly-managed roles, only users from the requesting account are included.
        team_names:
          type: array
          items:
            type: string
          description: Names of teams that have this role assigned. For Firefly-managed roles, only teams from the requesting account are included.
        firefly_managed:
          type: boolean
          description: Whether this role is managed by Firefly (system-wide, non-editable role)
        created_at:
          type: string
          format: date-time
          description: When the role was created
        updated_at:
          type: string
          format: date-time
          description: When the role was last updated
    RoleUser:
      type: object
      required:
      - name
      properties:
        name:
          type: string
          description: User's name
        profile_photo:
          type: string
          nullable: true
          description: URL to user's profile photo
    RoleScope:
      type: object
      required:
      - scope_id
      - scope_name
      properties:
        scope_id:
          type: integer
          description: ID of the scope definition
          example: 4
        scope_name:
          type: string
          description: Name of the scope (e.g., inventory:read, workflows:*)
          example: inventory:read
    RoleScopeInput:
      type: object
      required:
      - scope_id
      properties:
        scope_id:
          type: integer
          description: ID of the scope to assign to the role
          example: 4
    UserSearchRequest:
      type: object
      properties:
        search:
          type: string
          maxLength: 255
          description: Search users by name or email using full-text search
          example: john@example.com
        type:
          type: string
          enum:
          - USER
          - SA
          description: Filter by user type - either regular USER or Service Account (SA)
          example: USER
        role_ids:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 50
          description: Filter by role IDs - users must have at least one of these roles
          example:
          - 550e8400-e29b-41d4-a716-446655440000
        team_ids:
          type: array
          items:
            type: string
            format: uuid
          maxItems: 50
          description: Filter by team IDs - users must be members of at least one of these teams
          example:
          - 660f9511-f3ac-52e5-b827-557766551111
        limit:
          type: integer
          minimum: 1
          maximum: 100
          default: 25
          description: Maximum number of users to return
          example: 25
        offset:
          type: integer
          minimum: 0
          default: 0
          description: Number of users to skip
          example: 0
    UserCreateRequest:
      type: object
      required:
      - name
      - type
      properties:
        name:
          type: string
          description: User's name
        type:
          type: string
          enum:
          - USER
          - SA
          description: User type - either regular USER or Service Account (SA)
        email:
          type: string
          format: email
          description: User's email address (required for type 'user', optional for type 'SA')
        description:
          type: string
          nullable: true
          description: User's description or bio (optional, commonly used for SA)
        role_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of role IDs to assign to the user
        team_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of team IDs to add the user to
        profile_photo:
          type: string
          format: uri
          nullable: true
          description: URL to user's profile photo
        created_by:
          type: string
          format: email
          nullable: true
          description: Email address of the person creating this user (will be looked up in the database)
        onboarding_user:
          type: boolean
          default: false
          description: If true, automatically assigns the 'Admin' role (from account_id=null) to the user
        is_sso:
          type: boolean
          default: false
          description: If true, skips Auth0 user creation and password reset email. Use this flag for SSO users managed externally.
    UserUpdateRequest:
      type: object
      properties:
        description:
          type: string
          nullable: true
          description: User's description or bio
        profile_photo:
          type: string
          format: uri
          nullable: true
          description: URL to user's profile photo
        role_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of role IDs to assign to the user (replaces existing roles)
        team_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of team IDs to assign to the user (replaces existing teams)
        connection:
          type: string
          description: Connection/authentication provider for the user
        email_verified:
          type: boolean
          description: Whether the user's email has been verified
        last_login:
          type: string
          format: date-time
          nullable: true
          description: Last login timestamp for the user (only updates if provided)
    UpdateUserTeamsRequest:
      type: object
      required:
      - email
      - team_names
      properties:
        email:
          type: string
          format: email
          description: Email of the user whose teams should be updated
          example: user@example.com
        team_names:
          type: array
          items:
            type: string
          description: List of team names the user should belong to
          example:
          - Engineering
          - DevOps
          - Security
          maxItems: 50
    UpdateUserTeamsResponse:
      type: object
      required:
      - attached_team_names
      properties:
        attached_team_names:
          type: array
          items:
            type: string
          description: List of team names that were successfully attached to the user
          example:
          - Engineering
          - DevOps
    TeamCreateRequest:
      type: object
      required:
      - name
      properties:
        name:
          type: string
          description: Team name
        description:
          type: string
          nullable: true
          description: Team description
        user_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of user IDs to add to the team
        attached_role_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of role IDs to assign to the team
    TeamUpdateRequest:
      type: object
      properties:
        name:
          type: string
          description: Team name
        description:
          type: string
          nullable: true
          description: Team description
        user_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of user IDs that belong to this team
        attached_role_ids:
          type: array
          items:
            type: string
            format: uuid
          description: List of role IDs assigned to this team
    ApiKeyCreateRequest:
      type: object
      required:
      - type
      properties:
        type:
          type: string
          enum:
          - TEAM
          - USER
          description: Type of API key (scope)
        user_id:
          type: string
          format: uuid
          nullable: true
          description: User ID (required when type is USER)
        team_id:
          type: string
          format: uuid
          nullable: true
          description: Team ID (required when type is TEAM)
        alias:
          type: string
          maxLength: 255
          nullable: true
          description: Human-readable alias for the API key
        description:
          type: string
          nullable: true
          description: Description of the API key's purpose
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: When the API key should expire (must be in the future, RFC3339 format)
        created_by:
          type: string
          format: email
          nullable: true
          description: Email address of the person creating this API key (will be looked up in the database)
        system_generated:
          type: boolean
          nullable: true
          default: false
          description: If true, creates an SA type user with admin role and attaches the API key to it (similar to migration logic)
    ApiKeyRotateRequest:
      type: object
      properties:
        alias:
          type: string
          maxLength: 255
          nullable: true
          description: Human-readable alias for the API key
        description:
          type: string
          nullable: true
          description: Description of the API key's purpose
        expires_at:
          type: string
          format: date-time
          nullable: true
          description: When the API key should expire (must be in the future, RFC3339 format)
    RoleCreateRequest:
      type: object
      required:
      - name
      - scopes
      properties:
        name:
          type: string
          description: Role name
        description:
          type: string
          nullable: true
          description: Role description
        integrationIds:
          type: array
          items:
            type: string
          description: Optional list of integration IDs to restrict role's access to specific integrations
          example:
          - integration-123
          - integration-456
        providers:
          type: array
          items:
            type: string
          description: Optional list of provider types to restrict role's access to specific providers
          example:
          - aws
          - azure
          - gcp
        scopes:
          type: array
          items:
            $ref: '#/components/schemas/RoleScopeInput'
          description: List of scopes to assign to the role
    RoleUpdateRequest:
      type: object
      properties:
        name:
          type: string
          description: Role name
        description:
          type: string
          nullable: true
          description: Role description
        integrationIds:
          type: array
          items:
            type: string
          description: Optional list of integration IDs to restrict role's access to specific integrations
          example:
          - integration-123
          - integration-456
        providers:
          type: array
          items:
            type: string
          description: Optional list of provider types to restrict role's access to specific providers
          example:
          - aws
          - azure
          - gcp
        scopes:
          type: array
          items:
            $ref: '#/components/schemas/RoleScopeInput'
          description: List of scopes to assign to the role
    UserResponse:
      allOf:
      - $ref: '#/components/schemas/User'
    UserListResponse:
      type: object
      properties:
        users:
          type: array
          items:
            $ref: '#/components/schemas/User'
        total_count:
          type: integer
          description: Total number of users matching the filter criteria
          example: 42
    TeamResponse:
      allOf:
      - $ref: '#/components/schemas/Team'
    TeamListResponse:
      type: object
      properties:
        teams:
          type: array
          items:
            $ref: '#/components/schemas/Team'
        total_count:
          type: integer
          description: Total number of teams matching the filter criteria
          example: 42
    ApiKeyResponse:
      allOf:
      - $ref: '#/components/schemas/ApiKey'
    ApiKeyListResponse:
      type: object
      properties:
        api_keys:
          type: array
          items:
            $ref: '#/components/schemas/ApiKey'
        total_count:
          type: integer
          description: Total number of API keys matching the filter criteria
          example: 42
    ApiKeyCreateResponse:
      allOf:
      - $ref: '#/components/schemas/ApiKey'
      - type: object
        required:
        - secret
        properties:
          secret:
            type: string
            description: The API key secret (only returned on creation, plaintext with ffl_live_ prefix)
    RoleResponse:
      allOf:
      - $ref: '#/components/schemas/Role'
    RoleListResponse:
      type: object
      properties:
        roles:
          type: array
          items:
            $ref: '#/components/schemas/Role'
        total_count:
          type: integer
          description: Total number of roles matching the filter criteria
          example: 42
    UserPermissionsByEmailResponse:
      type: object
      required:
      - is_legacy
      - permissions
      - user_id
      - is_email_verified
      properties:
        is_legacy:
          type: boolean
          description: Whether this account uses legacy RBAC (true) or new RBAC (false). Determined by RBAC_ENABLED_ACCOUNTS environment variable.
          example: true
        permissions:
          type: array
          items:
            type: object
            required:
            - action
            - resource_filter
            properties:
              action:
                type: string
                description: The permission scope/action (e.g., workflows:read, inventory:write)
                example: workflows:projects:read
              resource_filter:
                type: array
                items:
                  type: string
                description: Optional filters to restrict access to specific resources
                example:
                - project_id:int_123
          description: All effective permissions for the user
        user_id:
          type: string
          description: The user ID (UUID format)
          example: abc123
        is_email_verified:
          type: boolean
          description: Whether the user's email has been verified (false if not set or null in database)
          default: false
    Error:
      type: object
      required:
      - error
      - message
      properties:
        error:
          type: string
          description: Error code
        message:
          type: string
          description: Human-readable error message
        details:
          type: object
          description: Additional error details
    HealthCheck:
      type: object
      required:
      - status
      - timestamp
      properties:
        status:
          type: string
          description: Health status
          example: ok
        timestamp:
          type: string
          format: date-time
          description: Timestamp when the health check was performed
    LoginRequest:
      type: object
      required:
      - accessKey
      - secretKey
      properties:
        accessKey:
          type: string
          description: API key identifier (INFL format, 20 uppercase letters)
          example: INFLMPUCPIXHBRMBAUGQ
        secretKey:
          type: string
          description: Firefly API secret
          example: ABC123XYZ456...
    RefreshRequest:
      type: object
      required:
      - refresh_token
      properties:
        refresh_token:
          type: string
          description: JWT refresh token
    AuthorizeRequest:
      type: object
      required:
      - access_token
      properties:
        access_token:
          type: string
          description: JWT access token to verify
    AuthorizeResponse:
      type: object
      required:
      - valid
      - account_id
      properties:
        valid:
          type: boolean
          description: Whether the token is valid
          example: true
        account_id:
          type: string
          description: Account ID from the token
        api_key_id:
          type: string
          format: uuid
          description: API key ID from the token
        user_id:
          type: string
          format: uuid
          nullable: true
          description: User ID if this is a user-scoped token
        team_id:
          type: string
          format: uuid
          nullable: true
          description: Team ID if this is a team-scoped token
        expires_at:
          type: string
          format: date-time
          description: When the token expires
    LoginResponse:
      type: object
      required:
      - accessToken
      - expiresAt
      - tokenType
      properties:
        accessToken:
          type: string
          description: JWT access token
        expiresAt:
          type: integer
          description: Unix timestamp when the token expires
          example: 1735689600
        tokenType:
          type: string
          enum:
          - Bearer
          description: Token type for Authorization header
          example: Bearer
    Scope:
      type: object
      required:
      - id
      - name
      - label
      - category
      - sort_priority
      properties:
        id:
          type: integer
          description: Unique identifier for the scope
        name:
          type: string
          description: Scope name (e.g., 'inventory:read')
          example: inventory:read
        label:
          type: string
          description: Human-readable label for the scope
          example: Inventory Read
        category:
          type: string
          description: Scope category (e.g., 'inventory', 'workflows')
          example: inventory
        parent_id:
          type: integer
          nullable: true
          description: Parent scope ID for hierarchical structure
        sort_priority:
          type: integer
          description: Sorting priority for parent scopes (lower number = higher priority, appears first). Used for ordering parent scopes in the tree.
          example: 10
        description:
          type: string
          nullable: true
          description: Detailed description of the scope
        filters:
          type: array
          items:
            type: string
          description: Available filter names for this scope (e.g., ["provider", "integration_type"])
        children:
          type: array
          items:
            $ref: '#/components/schemas/Scope'
          description: Child scopes for tree structure
    ScopeTreeResponse:
      type: object
      required:
      - scopes
      properties:
        scopes:
          type: array
          items:
            $ref: '#/components/schemas/Scope'
          description: Tree-structured list of scopes
    MigrationResponse:
      type: object
      required:
      - total_users_in_auth0
      - users_migrated
      - users_skipped
      - users_failed
      - api_keys_migrated
      properties:
        total_users_in_auth0:
          type: integer
          description: Total number of users found in Auth0 for this account
          example: 25
        users_migrated:
          type: integer
          description: Number of users successfully migrated to the database
          example: 20
        users_skipped:
          type: integer
          description: Number of users skipped (already exist in database)
          example: 3
        users_failed:
          type: integer
          description: Number of users that failed to migrate
          example: 2
        api_keys_migrated:
          type: integer
          description: Number of API keys successfully migrated to the database
          example: 15
        failed_users:
          type: array
          items:
            type: object
            properties:
              email:
                type: string
                format: email
                description: Email of the user that failed to migrate
              error:
                type: string
                description: Error message
          description: List of users that failed to migrate with error details
        message:
          type: string
          description: Summary message
          example: 'Migration completed: 20 users migrated, 3 skipped, 2 failed, 15 API keys migrated'
    ChangeUserAccountRequest:
      type: object
      required:
      - email
      - new_account_id
      properties:
        email:
          type: string
          format: email
          description: Email of the user whose account should be changed
          example: user@example.com
        new_account_id:
          type: string
          description: The new account ID to assign to the user
          example: new-account-123
    ChangeUserAccountResponse:
      type: object
      required:
      - success
      - user_id
      - email
      - old_account_id
      - new_account_id
      - auth0_updated
      - changes
      properties:
        success:
          type: boolean
          description: Whether the account change was successful
          example: true
        user_id:
          type: string
          format: uuid
          description: UUID of the user whose account was changed
        email:
          type: string
          format: email
          description: Email of the user
        old_account_id:
          type: string
          description: The previous account ID
        new_account_id:
          type: string
          description: The new account ID
        auth0_updated:
          type: boolean
          description: Whether Auth0 app_metadata was successfully updated. If false, database was updated but Auth0 sync failed.
        changes:
          type: object
          required:
          - account_updated
          - user_api_keys_deleted
          - team_memberships_cleared
          - account_roles_removed
          - global_roles_kept
          properties:
            account_updated:
              type: boolean
              description: Whether the account_id was updated in the database
            user_api_keys_deleted:
              type: integer
              description: Number of user-scoped API keys deleted
            team_memberships_cleared:
              type: integer
              description: Number of team memberships removed
            account_roles_removed:
              type: integer
              description: Number of account-specific roles removed
            global_roles_kept:
              type: integer
              description: Number of global roles retained
    Auth0Event:
      type: object
      description: Auth0 CloudEvents format webhook event
      required:
      - id
      - type
      - specversion
      - source
      - time
      - data
      properties:
        id:
          type: string
          description: Unique event identifier
          example: evt_kZiZBuaLKCnyX3BPypxiaB
        type:
          type: string
          description: Event type
          example: user.deleted
        specversion:
          type: string
          description: CloudEvents spec version
          example: '1.0'
        source:
          type: string
          description: Event source
          example: urn:auth0:dev-firefly.eu.auth0.com
        time:
          type: string
          format: date-time
          description: Event timestamp
          example: '2025-11-21T10:09:39.155Z'
        a0stream:
          type: string
          description: Auth0 stream identifier
          example: est_ecYKqNewx2E4R9R9WcgCnv
        a0tenant:
          type: string
          description: Auth0 tenant identifier
          example: dev-firefly
        data:
          $ref: '#/components/schemas/Auth0EventData'
    Auth0EventData:
      type: object
      required:
      - object
      properties:
        object:
          $ref: '#/components/schemas/Auth0DeletedUser'
    Auth0DeletedUser:
      type: object
      required:
      - user_id
      - email
      - deleted_at
      properties:
        user_id:
          type: string
          description: Auth0 user ID
          example: google-oauth2|103545469385979491843
        email:
          type: string
          format: email
          description: User's email address
          example: john.doe@gmail.com
        email_verified:
          type: boolean
          description: Whether the user's email was verified
        username:
          type: string
          description: Username
          example: johndoe
        phone_number:
          type: string
          description: Phone number
          example: '+15555555555'
        phone_verified:
          type: boolean
          description: Whether the phone number was verified
        created_at:
          type: string
          format: date-time
          description: When the user was created in Auth0
          example: '2025-02-01T12:34:56Z'
        updated_at:
          type: string
          format: date-time
          description: When the user was last updated in Auth0
          example: '2025-02-01T12:34:56Z'
        deleted_at:
          type: string
          format: date-time
          description: When the user was deleted from Auth0
          example: '2025-02-01T12:34:56Z'
        name:
          type: string
          description: User's full name
          example: John Doe
        nickname:
          type: string
          description: User's nickname
          example: John Doe
        picture:
          type: string
          description: URL to user's profile picture
          example: https://secure.gravatar.com/avatar/...
        given_name:
          type: string
          description: User's first name
          example: John
        family_name:
          type: string
          description: User's last name
          example: Doe
        last_ip:
          type: string
          description: Last IP address used by the user
          example: 10.0.0.1
        last_login:
          type: string
          format: date-time
          description: Last login timestamp
          example: '2025-02-01T12:34:56Z'
        logins_count:
          type: integer
          description: Total number of logins
          example: 42
        blocked:
          type: boolean
          description: Whether the user was blocked
          example: false
        identities:
          type: array
          description: User identity providers
          items:
            type: object
        app_metadata:
          type: object
          description: Application metadata
        user_metadata:
          type: object
          description: User metadata
        idp_tenant_domain:
          type: string
          description: IDP tenant domain
          example: firefly.ai
        multifactor_last_modified:
          type: string
          format: date-time
          description: When multifactor was last modified
