> ## Documentation Index
> Fetch the complete documentation index at: https://docs.humanly.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Analytics

> Retrieve comprehensive analytics and metrics for your recruitment process

## Overview

The Analytics API provides comprehensive metrics and insights for your recruitment process. It exposes data for candidates, interviews, and candidate interviews (phone screens), allowing you to track performance, completion rates, and feedback.

## Get Analytics

Retrieve comprehensive analytics data grouped by resource type.

**Endpoint:** `GET /qsi/gather/analytics`

<ParamField name="startDate" type="string">
  Start date in ISO 8601 format (e.g., `2023-01-01`). Defaults to 30 days ago.
</ParamField>

<ParamField name="endDate" type="string">
  End date in ISO 8601 format (e.g., `2023-01-31`). Defaults to today.
</ParamField>

<ParamField name="teamId" type="string">
  Override team for the request
</ParamField>

<ParamField name="userId" type="string">
  Filter analytics by specific user (recruiter)
</ParamField>

<ParamField name="interviewId" type="string">
  Filter analytics by specific interview template
</ParamField>

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET https://api.prod.qualifi.hr/qsi/gather/analytics \
      -H "x-api-key: ${API_KEY}"
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch('https://api.prod.qualifi.hr/qsi/gather/analytics', {
      method: 'GET',
      headers: {
        'x-api-key': apiKey
      }
    });
    const analytics = await response.json();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    response = requests.get(
        'https://api.prod.qualifi.hr/qsi/gather/analytics',
        headers={
            'x-api-key': api_key
        }
    )
    analytics = response.json()
    ```
  </Tab>
</Tabs>

### Custom Date Range

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET "https://api.prod.qualifi.hr/qsi/gather/analytics?startDate=2023-01-01&endDate=2023-03-31" \
      -H "x-api-key: ${API_KEY}"
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const params = new URLSearchParams({
      startDate: '2023-01-01',
      endDate: '2023-03-31'
    });

    const response = await fetch(`https://api.prod.qualifi.hr/qsi/gather/analytics?${params}`, {
      method: 'GET',
      headers: {
        'x-api-key': apiKey
      }
    });
    const analytics = await response.json();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    params = {
        'startDate': '2023-01-01',
        'endDate': '2023-03-31'
    }

    response = requests.get(
        'https://api.prod.qualifi.hr/qsi/gather/analytics',
        headers={'x-api-key': api_key},
        params=params
    )
    analytics = response.json()
    ```
  </Tab>
</Tabs>

### Filter by User

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET "https://api.prod.qualifi.hr/qsi/gather/analytics?userId=user-uuid" \
      -H "x-api-key: ${API_KEY}"
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch('https://api.prod.qualifi.hr/qsi/gather/analytics?userId=user-uuid', {
      method: 'GET',
      headers: {
        'x-api-key': apiKey
      }
    });
    const analytics = await response.json();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    response = requests.get(
        'https://api.prod.qualifi.hr/qsi/gather/analytics',
        headers={'x-api-key': api_key},
        params={'userId': 'user-uuid'}
    )
    analytics = response.json()
    ```
  </Tab>
</Tabs>

### Filter by Interview Template

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X GET "https://api.prod.qualifi.hr/qsi/gather/analytics?interviewId=interview-uuid" \
      -H "x-api-key: ${API_KEY}"
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch('https://api.prod.qualifi.hr/qsi/gather/analytics?interviewId=interview-uuid', {
      method: 'GET',
      headers: {
        'x-api-key': apiKey
      }
    });
    const analytics = await response.json();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    import requests

    response = requests.get(
        'https://api.prod.qualifi.hr/qsi/gather/analytics',
        headers={'x-api-key': api_key},
        params={'interviewId': 'interview-uuid'}
    )
    analytics = response.json()
    ```
  </Tab>
</Tabs>

<CodeGroup>
  ```json Response theme={null}
  {
    "data": {
      "candidates": {
        "total": 150,
        "archived": 45
      },
      "interviews": {
        "total": 10,
        "active": 8,
        "archived": 2,
        "standard": 8,
        "questionnaire": 2
      },
      "candidateInterviews": {
        "total": 100,
        "statusBreakdown": {
          "inviteSent": 20,
          "newResponse": 15,
          "hasReviewed": 30,
          "partiallyCompleted": 5,
          "hired": 5,
          "archived": 20,
          "expired": 5
        },
        "completed": 50,
        "incomplete": 25,
        "completionRate": 0.5,
        "averageResponseTime": "2 days",
        "averageResponseTimeInHours": 48,
        "hoursSaved": 25,
        "positiveFeedbackPercentage": 80
      },
      "dateRange": {
        "startDate": "2023-01-01T00:00:00.000Z",
        "endDate": "2023-01-31T23:59:59.999Z"
      }
    },
    "meta": {
      "requestId": "req-123",
      "timestamp": "2023-02-01T12:00:00.000Z",
      "cached": false
    }
  }
  ```
</CodeGroup>

## Response Structure

### Candidates Analytics

Metrics related to candidate entities.

* **total**: Total unique candidates found in the date range
* **archived**: Candidates that have been archived

### Interviews Analytics

Metrics related to interview templates. These metrics are generally scoped to the team and organization, not strictly by date range (showing currently available templates).

* **total**: Total interview templates
* **active**: Currently active templates
* **archived**: Archived templates
* **standard**: Standard audio interviews
* **questionnaire**: Text-based questionnaire interviews

### Candidate Interviews Analytics

Metrics related to interview instances (phone screens) assigned to candidates. This is the primary section for performance metrics.

* **total**: Total interview instances in the date range
* **statusBreakdown**: Detailed count of interviews by current status
  * **inviteSent**: Invites that have been sent
  * **newResponse**: New responses awaiting review
  * **hasReviewed**: Responses that have been reviewed
  * **partiallyCompleted**: Partially completed interviews
  * **hired**: Candidates marked as hired
  * **archived**: Archived interviews
  * **expired**: Expired interviews
* **completed**: Count of completed interviews
* **incomplete**: Count of incomplete interviews
* **completionRate**: Ratio of completed interviews to total interviews (0.0 to 1.0)
* **averageResponseTime**: Human-readable average time from invite to completion
* **averageResponseTimeInHours**: Numeric average response time in hours
* **hoursSaved**: Estimated hours saved based on completed interviews (0.5 hours per interview)
* **positiveFeedbackPercentage**: Percentage of interviews rated positively

## Caching Behavior

To ensure performance, analytics results are cached based on the queried date range:

* **Date range ≤ 1 day**: Cached for 5 minutes
* **Date range 2-7 days**: Cached for 15 minutes
* **Date range 8-30 days**: Cached for 1 hour
* **Date range > 30 days**: Cached for 2 hours

The `meta.cached` field in the response indicates if the data was served from cache (`true`) or computed fresh (`false`).

## Error Responses

<CodeGroup>
  ```json 401 Unauthorized theme={null}
  {
    "error": {
      "code": "UNAUTHORIZED",
      "message": "Missing organization context"
    },
    "meta": {
      "requestId": "req-123",
      "timestamp": "2023-02-01T12:00:00.000Z"
    }
  }
  ```

  ```json 400 Bad Request theme={null}
  {
    "error": {
      "code": "INVALID_TEAM",
      "message": "Team not found or not accessible"
    },
    "meta": {
      "requestId": "req-123",
      "timestamp": "2023-02-01T12:00:00.000Z"
    }
  }
  ```

  ```json 500 Internal Server Error theme={null}
  {
    "error": {
      "code": "INTERNAL_ERROR",
      "message": "Failed to retrieve analytics"
    },
    "meta": {
      "requestId": "req-123",
      "timestamp": "2023-02-01T12:00:00.000Z"
    }
  }
  ```
</CodeGroup>

## Chatbot Analytics (Aggregated)

Retrieve the aggregated funnel and time series for a single chatbot. The shape mirrors the in-app chatbot analytics.

**Endpoint:** `GET /qsi/gather/chatbots/{chatbotId}/analytics`

<ParamField path="chatbotId" type="string" required>
  UUID of the chatbot
</ParamField>

<ParamField query="startDate" type="string">
  Start of the date range (inclusive). Applied only when both `startDate` and `endDate` are provided.
</ParamField>

<ParamField query="endDate" type="string">
  End of the date range (exclusive).
</ParamField>

<CodeGroup>
  ```json Response theme={null}
  {
    "data": {
      "summary": {
        "totalConversations": 12,
        "totalMessages": 84,
        "totalApplicationsStarted": 5,
        "totalApplicationsCompleted": 3,
        "totalLeadsCaptured": 7,
        "applicationConversionRate": 60,
        "averageMessagesPerConversation": 7
      },
      "timeSeries": [
        { "date": "2026-01-01", "conversations": 2, "messages": 14, "applications": 1 }
      ]
    },
    "meta": { "requestId": "uuid", "timestamp": "2026-01-01T00:00:00Z" }
  }
  ```
</CodeGroup>

`applicationConversionRate` is a percentage (0–100).

## Chatbot Analytics Events (Raw)

Retrieve the raw analytics event rows for a chatbot, page paginated and ordered newest first.

**Endpoint:** `GET /qsi/gather/chatbots/{chatbotId}/analytics/events`

<ParamField path="chatbotId" type="string" required>
  UUID of the chatbot
</ParamField>

<ParamField query="page" type="number">
  Page number (default: 1)
</ParamField>

<ParamField query="pageSize" type="number">
  Items per page (default: 50)
</ParamField>

<ParamField query="startDate" type="string">
  Start of the date range (inclusive). Applied only with `endDate`.
</ParamField>

<ParamField query="endDate" type="string">
  End of the date range (exclusive).
</ParamField>

<CodeGroup>
  ```json Response theme={null}
  {
    "data": {
      "events": [
        {
          "id": "event-uuid",
          "eventType": "message_sent",
          "occurredAt": "2026-01-01T00:00:05Z",
          "conversationId": "conv-uuid",
          "metadata": { "role": "USER" },
          "chatId": "chatbot-uuid",
          "organizationId": "org-uuid",
          "teamId": "team-uuid",
          "createdAt": "2026-01-01T00:00:05Z",
          "updatedAt": "2026-01-01T00:00:05Z"
        }
      ],
      "pagination": { "total": 84, "page": 1, "totalPages": 2, "pageSize": 50 }
    },
    "meta": { "requestId": "uuid", "timestamp": "2026-01-01T00:00:00Z" }
  }
  ```
</CodeGroup>
