openapi: 3.0.3
info:
  title: INFIMA All APIs
  description: Combined OpenAPI 3.0 specification covering Partner, Client, User, Reports, Phishing, and Sent Emails APIs
  version: 1.0.0
  contact:
    name: INFIMA Security API Support
    url: https://kb.infimasec.com/docs/reporting-api/

servers:
  - url: https://app.infimasecapis.com/v1
    description: Production API server

security:
  - ApiKeyAuth: []

paths:
  /partner:
    get:
      summary: Get Partner
      description: Retrieves data for a partner. A partner manages Security Awareness Training for multiple clients.
      operationId: getPartner
      tags:
        - Partner
      responses:
        '200':
          description: Successfully retrieved partner information
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PartnerResponse'
        '401':
          description: Unauthorized - Missing or invalid API key
        '500':
          description: Internal server error

  /clients:
    get:
      summary: Get Clients
      description: Retrieves data for all clients associated with an INFIMA account.
      operationId: getClients
      tags:
        - Client
      parameters:
        - name: limit
          in: query
          description: Maximum number of objects to return. Default 20. Minimum 1. Maximum 50.
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: The index of the first object to return. Default 0.
          schema:
            type: integer
            default: 0
        - name: ids
          in: query
          description: The ids of specified clients to return
          schema:
            type: array
            items:
              type: integer
      responses:
        '200':
          description: Successfully retrieved clients
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ClientListResponse'
        '401':
          description: Unauthorized - Missing or invalid API key
        '500':
          description: Internal server error

  /clients/{client_id}/users:
    get:
      summary: Get Users
      description: Retrieves data for all users for a given client.
      operationId: getUsers
      tags:
        - User
      parameters:
        - name: client_id
          in: path
          required: true
          description: The id of the client to return users for
          schema:
            type: integer
        - name: limit
          in: query
          description: Maximum number of objects to return. Default 20. Minimum 1. Maximum 50.
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: The index of the first object to return. Default 0.
          schema:
            type: integer
            default: 0
        - name: status
          in: query
          description: Filter users by status. Default active.
          schema:
            type: string
            enum:
              - active
              - inactive
              - all
            default: active
      responses:
        '200':
          description: Successfully retrieved users
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UserListResponse'
        '401':
          description: Unauthorized - Missing or invalid API key
        '500':
          description: Internal server error

  /users/{user_id}:
    post:
      summary: Update User
      description: >-
        Updates a user's status, preferred language, and/or role. Only the
        fields provided in the request body are changed (partial update). At
        least one field must be provided.
      operationId: updateUser
      tags:
        - User
      parameters:
        - name: user_id
          in: path
          required: true
          description: The id of the user to update
          schema:
            type: string
            format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/UpdateUserRequest'
      responses:
        '200':
          description: User updated successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/UpdateUserResponse'
        '400':
          description: Bad request - no updatable fields provided, or an invalid value
        '401':
          description: Unauthorized - Missing or invalid API key
        '404':
          description: User not found
        '500':
          description: Internal server error

  /users/{user_id}/training:
    get:
      summary: Get User Training Results
      description: Retrieves training data for a specific user.
      operationId: getUserTrainingResults
      tags:
        - User
      parameters:
        - name: user_id
          in: path
          required: true
          description: The id of the user
          schema:
            type: string
            format: uuid
        - name: limit
          in: query
          description: Maximum number of objects to return. Default 20. Minimum 1. Maximum 50.
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: The index of the first object to return. Default 0.
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Successfully retrieved training results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/TrainingResultsListResponse'
        '401':
          description: Unauthorized - Missing or invalid API key
        '500':
          description: Internal server error

  /users/{user_id}/phishing:
    get:
      summary: Get User Phishing Results
      description: Retrieves phishing data for a specific user.
      operationId: getUserPhishingResults
      tags:
        - User
      parameters:
        - name: user_id
          in: path
          required: true
          description: The id of the user
          schema:
            type: string
            format: uuid
        - name: limit
          in: query
          description: Maximum number of objects to return. Default 20. Minimum 1. Maximum 50.
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: The index of the first object to return. Default 0.
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Successfully retrieved phishing results
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PhishingResultsListResponse'
        '401':
          description: Unauthorized - Missing or invalid API key
        '500':
          description: Internal server error

  /clients/{client_id}/reports:
    get:
      summary: Get Reports
      description: Retrieves all reports for a given client.
      operationId: getReports
      tags:
        - Reports
      parameters:
        - name: client_id
          in: path
          required: true
          description: The id of the client to return reports for
          schema:
            type: integer
        - name: limit
          in: query
          description: Maximum number of objects to return. Default 20. Minimum 1. Maximum 50.
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: The index of the first object to return. Default 0.
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Successfully retrieved reports
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportListResponse'
        '401':
          description: Unauthorized - Missing or invalid API key
        '500':
          description: Internal server error

  /clients/{client_id}/reports/{report_id}:
    get:
      summary: Download Report
      description: Retrieves a download link to a specific report for a given client.
      operationId: downloadReport
      tags:
        - Reports
      parameters:
        - name: client_id
          in: path
          required: true
          description: The id of the client to return the report for
          schema:
            type: integer
        - name: report_id
          in: path
          required: true
          description: The id of the desired report
          schema:
            type: string
            format: uuid
        - name: limit
          in: query
          description: Maximum number of objects to return. Default 20. Minimum 1. Maximum 50.
          schema:
            type: integer
            default: 20
        - name: offset
          in: query
          description: The index of the first object to return. Default 0.
          schema:
            type: integer
            default: 0
      responses:
        '200':
          description: Successfully retrieved report download link
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ReportDownloadResponse'
        '401':
          description: Unauthorized - Missing or invalid API key
        '404':
          description: Report not found
        '500':
          description: Internal server error

  /sendphishing:
    post:
      summary: Send Phishing
      description: Sends a simulated phishing email to a specified user.
      operationId: sendPhishing
      tags:
        - Phishing
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SendPhishingRequest'
      responses:
        '200':
          description: Phishing email scheduled successfully
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SendPhishingResponse'
        '400':
          description: Bad request - Invalid parameters or missing required fields
        '401':
          description: Unauthorized - Missing or invalid API key
        '500':
          description: Internal server error

  /sentemails:
    post:
      summary: Retrieve Sent Emails
      description: |
        Retrieves sent email records for users within the partner's managed clients.
        Returns up to 30 days of email events from the specified start time.
        If no start time is provided, returns the last 30 days of events.
      operationId: getSentEmails
      tags:
        - Sent Emails
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SentEmailRequest'
            examples:
              byUserId:
                summary: Query by user ID
                value:
                  user_infima_id: "c66ce2a3-829d-46ee-820e-28698671c3d5"
                  start_time: "2024-01-15T00:00:00Z"
              byEmail:
                summary: Query by email address
                value:
                  email_address: "user@example.com"
                  start_time: "2024-01-15T00:00:00Z"
              withMessageTypeFilter:
                summary: Filter by message types
                value:
                  user_infima_id: "c66ce2a3-829d-46ee-820e-28698671c3d5"
                  message_types: ["training-invite", "phishing"]
                  start_time: "2024-01-15T00:00:00Z"
      responses:
        '200':
          description: Successfully retrieved sent emails
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SentEmailResponse'
              example:
                items:
                  - message_infima_id: "a4f8d2e1-7b3c-4e6f-9d8a-1c5e3f7a9b2d"
                    user_infima_id: "c66ce2a3-829d-46ee-820e-28698671c3d5"
                    event_time: "2024-01-20T14:30:00Z"
                    from_email: "training@infimasec.com"
                    subject: "Complete your security awareness training"
                    send_method: "microsoft-api"
                    message_type: "training-invite"
                  - message_infima_id: "b7e4f9c2-5a8d-4f1e-8c3b-2d6a9f8e7c5b"
                    user_infima_id: "c66ce2a3-829d-46ee-820e-28698671c3d5"
                    event_time: "2024-01-18T09:15:00Z"
                    from_email: "phishing-test@infimasec.com"
                    subject: "Important: Update your password"
                    send_method: "smtp"
                    message_type: "phishing"
                limit: 100
                offset: 0
                total: 2
        '400':
          description: Bad request - Invalid parameters or missing required fields
        '401':
          description: Unauthorized - Missing or invalid API key
        '403':
          description: Forbidden - User not found in partner's managed clients
        '404':
          description: Not found - Specified user does not exist
        '429':
          description: Too many requests - Rate limit exceeded
        '500':
          description: Internal server error

components:
  securitySchemes:
    ApiKeyAuth:
      type: apiKey
      in: header
      name: X-API-Key
      description: API key for authentication. To obtain a new API key, register one through the INFIMA Partner Dashboard.

  schemas:
    PartnerResponse:
      type: object
      required:
        - partner_name
        - created_date
        - admins
      properties:
        partner_name:
          type: string
          description: The partner's name
          example: "Partner Co"
        created_date:
          type: string
          format: date-time
          description: The date the partner was created (ISO 8601 format UTC)
          example: "2010-02-04T18:37:01Z"
        admins:
          type: array
          items:
            $ref: '#/components/schemas/Admin'
          description: The admins at the partner

    Admin:
      type: object
      required:
        - id
        - email
        - role
        - created_date
      properties:
        id:
          type: string
          format: uuid
          description: The admin's id
          example: "521f055b-e0cf-5bcd-9ce0-a412d194d544"
        email:
          type: string
          format: email
          description: The admin's email address
          example: "john.doe@partner.co"
        role:
          type: string
          description: The admin's role. Either User or Administrator.
          example: "Administrator"
        first_name:
          type: string
          description: The admin's first name
          example: "John"
        last_name:
          type: string
          description: The admin's last name
          example: "Doe"
        created_date:
          type: string
          format: date-time
          description: The date the admin was created (ISO 8601 format UTC)
          example: "2010-10-17T17:37:54Z"

    ClientListResponse:
      type: object
      required:
        - items
        - limit
        - offset
        - total
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Client'
        limit:
          type: integer
          description: Maximum number of objects returned
          example: 2
        offset:
          type: integer
          description: Number of items skipped
          example: 0
        total:
          type: integer
          description: Total number of items available
          example: 20

    Client:
      type: object
      required:
        - id
        - client_name
        - created_date
        - user_count
        - inactive_user_count
        - phishing_click_rate_total
        - phishing_click_rate_last_year
        - training_on_track_rate
      properties:
        id:
          type: integer
          description: The client's id
          example: 1
        client_name:
          type: string
          description: The client's name
          example: "Client 1"
        created_date:
          type: string
          format: date-time
          description: The date the client was created (ISO 8601 format UTC)
          example: "2010-02-04T18:37:01Z"
        user_count:
          type: integer
          description: The number of active users at the client
          example: 500
        inactive_user_count:
          type: integer
          description: The number of inactive (deactivated) users at the client
          example: 12
        phishing_click_rate_total:
          type: number
          format: float
          description: The phishing click rate for the entire client. Values range from 0-100.
          example: 25.0
        phishing_click_rate_last_year:
          type: number
          format: float
          description: The phishing click rate for the last year. Values range from 0-100.
          example: 25.0
        training_on_track_rate:
          type: number
          format: float
          description: The percentage of users at a client who are On-Track. Values range from 0-100.
          example: 33.3333

    UserListResponse:
      type: object
      required:
        - items
        - limit
        - offset
        - total
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/User'
        limit:
          type: integer
          example: 2
        offset:
          type: integer
          example: 0
        total:
          type: integer
          example: 5

    User:
      type: object
      required:
        - id
        - email
        - first_name
        - last_name
        - department
        - status
        - preferred_language
        - role
        - created_date
        - phishing_click_rate_total
        - phishing_click_rate_last_year
        - training_on_track
        - next_course
        - courses_behind
        - risk_score
      properties:
        id:
          type: string
          format: uuid
          description: The user's id
          example: "521226a6-1f4f-520d-aedb-205cf50990d5"
        email:
          type: string
          format: email
          description: The user's email address
          example: "joe@companya.com"
        first_name:
          type: string
          example: "Joe"
        last_name:
          type: string
          example: "Doe"
        department:
          type: string
          example: "HR"
        status:
          type: string
          enum:
            - active
            - inactive
          description: Whether the user is active or inactive
          example: "active"
        preferred_language:
          type: string
          enum:
            - en
            - es
            - fr-ca
          description: The user's preferred training-content language
          example: "en"
        role:
          type: string
          enum:
            - admin
            - executive
            - hr
            - finance
            - standard
          description: The user's risk role. Unclassified users are reported as "standard".
          example: "standard"
        created_date:
          type: string
          format: date-time
          example: "2010-01-01T00:00:00Z"
        phishing_click_rate_total:
          type: number
          format: float
          description: The percentage of phishing attacks clicked on. Values range from 0-100.
          example: 20.0
        phishing_click_rate_last_year:
          type: number
          format: float
          description: The percentage of phishing attacks clicked on in the last year. Values range from 0-100.
          example: 20.0
        training_on_track:
          type: boolean
          description: The user's training status. True if user is caught up on all courses.
          example: false
        next_course:
          type: string
          description: The name of the next course for the user to complete
          example: "Phishing"
        courses_behind:
          type: integer
          description: The number of courses the user needs to complete to be On-Track
          example: 2
        risk_score:
          type: integer
          description: The user's risk score
          example: 720

    UpdateUserRequest:
      type: object
      description: >-
        Body for updating a user. Only the fields present are changed; at least
        one must be provided.
      properties:
        status:
          type: string
          enum:
            - active
            - inactive
          description: The user's status
          example: "inactive"
        preferred_language:
          type: string
          enum:
            - en
            - es
            - fr-ca
          description: The user's preferred training-content language
          example: "es"
        role:
          type: string
          enum:
            - admin
            - executive
            - hr
            - finance
            - standard
          description: The user's risk role
          example: "executive"

    UpdateUserResponse:
      type: object
      required:
        - status
      properties:
        status:
          type: string
          description: Result indicator
          example: "updated"

    TrainingResultsListResponse:
      type: object
      required:
        - items
        - limit
        - offset
        - total
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/TrainingResults'
        limit:
          type: integer
          example: 20
        offset:
          type: integer
          example: 0
        total:
          type: integer
          example: 4

    TrainingResults:
      type: object
      required:
        - order
        - course_name
        - completed
        - completed_date
      properties:
        order:
          type: integer
          description: The order of the course. Begins with course 1.
          example: 1
        course_name:
          type: string
          description: The course name
          example: "Safe Web Usage"
        completed:
          type: boolean
          description: Has the user completed the course
          example: true
        completed_date:
          type: string
          format: date-time
          description: The date the user completed the course (ISO 8601 format UTC)
          example: "2010-06-07T18:36:17Z"

    PhishingResultsListResponse:
      type: object
      required:
        - items
        - limit
        - offset
        - total
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/PhishingResults'
        limit:
          type: integer
          example: 20
        offset:
          type: integer
          example: 0
        total:
          type: integer
          example: 9

    PhishingResults:
      type: object
      required:
        - status
        - status_date
      properties:
        status:
          type: string
          description: The status of the simulated phish event. Values can be Sent, Opened, Clicked.
          enum:
            - Sent
            - Opened
            - Clicked
          example: "Clicked"
        status_date:
          type: string
          format: date-time
          description: The date the status event occurred (ISO 8601 format UTC)
          example: "2010-12-11T17:45:04Z"

    ReportListResponse:
      type: object
      required:
        - items
        - limit
        - offset
        - total
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Report'
        limit:
          type: integer
          example: 0
        offset:
          type: integer
          example: 0
        total:
          type: integer
          example: 2

    Report:
      type: object
      required:
        - report_id
        - report_type
        - created_date
        - updated_at
      properties:
        report_id:
          type: string
          format: uuid
          description: The id of the report
          example: "521226a6-1f4f-520d-aedb-205cf50990d5"
        report_type:
          type: string
          description: The report type
          example: "phishing_overview"
        created_date:
          type: string
          format: date-time
          description: The date the report was created (ISO 8601 format UTC)
          example: "2010-01-01T00:00:00Z"
        updated_at:
          type: string
          format: date-time
          description: The date the report was updated (ISO 8601 format UTC)
          example: "2010-01-01T00:00:00Z"

    ReportDownloadResponse:
      type: object
      required:
        - items
        - limit
        - offset
        - total
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/ReportWithDownloadLink'
        limit:
          type: integer
          example: 2
        offset:
          type: integer
          example: 0
        total:
          type: integer
          example: 5

    ReportWithDownloadLink:
      allOf:
        - $ref: '#/components/schemas/Report'
        - type: object
          required:
            - download_link
          properties:
            download_link:
              type: string
              description: URL to download the report
              example: "infimasec.com/521226a6-1f4f-520d-aedb-205cf50990d5"

    SendPhishingRequest:
      type: object
      required:
        - user_id
        - phishing_template
      properties:
        user_id:
          type: string
          format: uuid
          description: The id of the user who will receive the phishing attempt
          example: "uf3fd541-03ec-4242-b4e8-b29425e95bdf"
        phishing_template:
          type: integer
          description: The id of the desired template
          example: 1
        send_time:
          type: string
          format: date-time
          description: The time at which the attempt will be sent in ISO 8601 format (UTC). If not provided, sends immediately.
          example: "2010-01-01T00:00:00Z"

    SendPhishingResponse:
      type: object
      required:
        - message
      properties:
        message:
          type: string
          description: Response message indicating success
          example: "Phishing email scheduled successfully"

    SentEmailRequest:
      type: object
      properties:
        user_infima_id:
          type: string
          format: uuid
          description: INFIMA user identifier
          example: "c66ce2a3-829d-46ee-820e-28698671c3d5"
        email_address:
          type: string
          format: email
          description: Email address of the user
          example: "user@example.com"
        message_types:
          type: array
          items:
            type: string
            enum:
              - training-invite
              - phishing
              - phish-reminder
              - certificate
              - monthly-report
          description: |
            Filter results to only include specified message types.
            If not provided, all message types are returned.
            Unknown message types are ignored silently.
            Note: New message types may be added at any time.
          example: ["training-invite", "phishing"]
        start_time:
          type: string
          format: date-time
          description: |
            Start time for the query range in ISO 8601 format (UTC).
            Returns up to 30 days of events from this time.
            If not provided, returns the last 30 days.
          example: "2024-01-15T00:00:00Z"
      oneOf:
        - required: [user_infima_id]
        - required: [email_address]
      example:
        user_infima_id: "c66ce2a3-829d-46ee-820e-28698671c3d5"
        message_types: ["training-invite", "phishing"]
        start_time: "2024-01-15T00:00:00Z"

    SentEmail:
      type: object
      required:
        - message_infima_id
        - user_infima_id
        - event_time
        - from_email
        - subject
        - send_method
        - message_type
      properties:
        message_infima_id:
          type: string
          format: uuid
          description: Unique identifier for the sent message
          example: "a4f8d2e1-7b3c-4e6f-9d8a-1c5e3f7a9b2d"
        user_infima_id:
          type: string
          format: uuid
          description: INFIMA user identifier
          example: "c66ce2a3-829d-46ee-820e-28698671c3d5"
        event_time:
          type: string
          format: date-time
          description: Time when the email was sent in ISO 8601 format (UTC)
          example: "2024-01-20T14:30:00Z"
        from_email:
          type: string
          format: email
          description: Sender email address
          example: "training@infimasec.com"
        subject:
          type: string
          description: Email subject line
          example: "Complete your security awareness training"
        send_method:
          type: string
          enum:
            - microsoft-api
            - smtp
            - gmail-api
          description: Method used to send the email
          example: "microsoft-api"
        message_type:
          type: string
          description: |
            Type of message sent. 
            **Compatibility Promise**: Existing values will never be removed or changed.
            New values may be added in future versions.
            Clients should handle unknown values gracefully.
          enum:
            - training-invite
            - phishing
            - phish-reminder
            - certificate
            - monthly-report
          example: "training-invite"

    SentEmailResponse:
      type: object
      required:
        - items
        - limit
        - offset
        - total
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/SentEmail'
          description: Array of sent email records
        limit:
          type: integer
          description: Maximum number of items returned
          example: 100
        offset:
          type: integer
          description: Number of items skipped
          example: 0
        total:
          type: integer
          description: Total number of items matching the query
          example: 2

    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: Error code for programmatic handling
              example: "INVALID_REQUEST"
            message:
              type: string
              description: Human-readable error message
              example: "At least one of user_infima_id or email_address must be provided"
            details:
              type: object
              description: Additional error details (optional)
              additionalProperties: true
