> ## 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.

# Interviews

> Create and manage interviews with questions and settings

## Overview

Interviews define the structure and content of phone interviews. You can create standard interviews with audio questions or questionnaire-type interviews with survey questions.

<Callout type="info">
  Interview status is represented as a numeric value: `0` = Active, `1` = Paused, `2` = Closed, `3` = Archived.
</Callout>

<Callout type="tip">
  Need to update multiple interviews at once? See the [Bulk Update Interviews](/api-reference/interviews-bulk-update) endpoint.
</Callout>

## Create Interview

Create a new interview. The API supports `standard` interviews and fully-configured
`ai_interviewer` interviews.

**Endpoint:** `POST /qsi/gather/interviews`

<Callout type="warning">
  Questionnaire-type interviews must be created through the Qualifi dashboard.
</Callout>

<ParamField name="title" type="string" required>
  Title of the interview
</ParamField>

<ParamField name="displayName" type="string" required>
  Display name shown to candidates
</ParamField>

<ParamField name="interviewType" type="string" required>
  Type of interview: `"standard"` or `"ai_interviewer"`.
</ParamField>

<ParamField name="description" type="string">
  Description of the interview
</ParamField>

<ParamField name="descriptionUrl" type="string">
  URL to a job description
</ParamField>

<ParamField name="descriptionFileName" type="string">
  File name for the job description attachment
</ParamField>

<ParamField name="language" type="string">
  Language code (default: `"en"`)
</ParamField>

<ParamField name="questionIds" type="string[]">
  Array of question UUIDs for standard interviews
</ParamField>

<ParamField name="surveyQuestions" type="object[]">
  Array of survey question objects. Each object contains:

  * `id` (string) — UUID of the survey question
  * `knockout` (boolean) — whether the question is a knockout question
</ParamField>

<ParamField name="messageGroupId" type="string">
  UUID of message group (uses default if not provided)
</ParamField>

<ParamField name="narratorId" type="string">
  UUID of narrator for TTS
</ParamField>

<ParamField name="resume" type="boolean">
  Whether resume is required (default: `false`)
</ParamField>

<ParamField name="webOnly" type="boolean">
  Web-only interview (default: `false`)
</ParamField>

<ParamField name="keywords" type="string[]">
  Array of keyword strings to associate with the interview
</ParamField>

<ParamField name="notificationSubscribers" type="string[]">
  Array of user UUIDs to receive notifications for this interview
</ParamField>

<ParamField name="audioMessageURL" type="string">
  URL of a custom audio message to play during the interview
</ParamField>

<ParamField name="audioMessageTitle" type="string">
  Title for the custom audio message
</ParamField>

### AI Interviewer fields

These apply when `interviewType` is `"ai_interviewer"`. The AI persona is generated
automatically from the configuration and regenerated when behavior changes; internal
persona identifiers and prompts are never returned.

<ParamField name="aiTextQuestionIds" type="string[]">
  Ordered AI text question UUIDs for the AI interview.
</ParamField>

<ParamField name="jobDescriptionText" type="string">
  Job description text used to ground the AI interviewer's questions.
</ParamField>

<ParamField name="welcomeInfo" type="string">
  Candidate-facing welcome information shown before the interview.
</ParamField>

<ParamField name="knowledgeBaseIds" type="string[]">
  Knowledge base UUIDs to attach to the interview.
</ParamField>

<ParamField name="scoreCardTopics" type="object[]">
  Optional scorecard created with the interview. Each topic contains:

  * `topic` (string) — topic name
  * `weight` (number) — relative weight, `0`–`100`
  * `description` (string, optional) — what the topic evaluates
  * `lookingFor` (string\[], optional) — signals to look for
  * `scoreDescriptions` (object, optional) — `{ level1, level3, level5 }` rubric strings

  When `description`, `lookingFor`, or `scoreDescriptions` are omitted, the API generates defaults.
</ParamField>

<ParamField name="aiConfiguration" type="object">
  AI interviewer behavior configuration:

  * `replicaId` (string) — avatar replica id (required for AI interviews; see [Replicas](/api-reference/replicas))
  * `askFollowUpQuestions` (boolean) — ask follow-up questions
  * `askToElaborate` (boolean) — ask the candidate to elaborate
  * `digDeeper` (boolean) — probe deeper on answers
  * `friendlyTone` (boolean) — friendly tone
  * `professionalTone` (boolean) — professional tone
  * `conversationalStyle` (boolean) — maintain a natural conversational flow
  * `audioOnly` (boolean) — audio-only (no video avatar)
  * `greetingMessage` (string) — custom opening greeting
  * `closedCaptions` (boolean) — enable closed captions
  * `callRecording` (boolean) — record the call
  * `captureResponses` (boolean) — capture candidate responses
  * `askCandidateQuestions` (boolean) — let the candidate ask questions
  * `language` (string) — interview language code (e.g. `"en"`)
  * `timeoutSeconds` (number) — inactivity timeout in seconds

  `conversationalContext` is read-only.
</ParamField>

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.prod.qualifi.hr/qsi/gather/interviews \
      -H "x-api-key: ${API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "title": "Software Engineer Interview",
        "displayName": "Software Engineer Interview",
        "interviewType": "standard",
        "questionIds": ["uuid1", "uuid2"],
        "surveyQuestions": [
          { "id": "survey-q-uuid", "knockout": false }
        ],
        "keywords": ["javascript", "react"],
        "language": "en"
      }'
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch('https://api.prod.qualifi.hr/qsi/gather/interviews', {
      method: 'POST',
      headers: {
        'x-api-key': apiKey,
        'Content-Type': 'application/json'
      },
      body: JSON.stringify({
        title: 'Software Engineer Interview',
        displayName: 'Software Engineer Interview',
        interviewType: 'standard',
        questionIds: ['uuid1', 'uuid2'],
        surveyQuestions: [
          { id: 'survey-q-uuid', knockout: false }
        ],
        keywords: ['javascript', 'react'],
        language: 'en'
      })
    });
    const interview = await response.json();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    response = requests.post(
        'https://api.prod.qualifi.hr/qsi/gather/interviews',
        headers={
            'x-api-key': api_key,
            'Content-Type': 'application/json'
        },
        json={
            'title': 'Software Engineer Interview',
            'displayName': 'Software Engineer Interview',
            'interviewType': 'standard',
            'questionIds': ['uuid1', 'uuid2'],
            'surveyQuestions': [
                {'id': 'survey-q-uuid', 'knockout': False}
            ],
            'keywords': ['javascript', 'react'],
            'language': 'en'
        }
    )
    interview = response.json()
    ```
  </Tab>
</Tabs>

<CodeGroup>
  ```json Request theme={null}
  {
    "title": "Software Engineer Interview",
    "displayName": "Software Engineer Interview",
    "interviewType": "standard",
    "description": "Technical interview for software engineering role",
    "language": "en",
    "questionIds": ["uuid1", "uuid2"],
    "surveyQuestions": [
      { "id": "survey-q-uuid", "knockout": false }
    ],
    "keywords": ["javascript", "react"]
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "interview": {
        "id": "interview-uuid",
        "title": "Software Engineer Interview",
        "displayName": "Software Engineer Interview",
        "interviewType": "standard",
        "status": 0,
        "description": "Technical interview for software engineering role",
        "language": "en",
        "resume": false,
        "webOnly": false,
        "messageGroupId": "msg-group-uuid",
        "narratorId": "narrator-uuid",
        "organizationId": "org-uuid",
        "teamId": "team-uuid",
        "createdById": "user-uuid",
        "createdAt": "2026-01-15T00:00:00Z",
        "updatedAt": "2026-01-15T00:00:00Z"
      }
    },
    "meta": {
      "requestId": "req-uuid",
      "timestamp": "2026-01-15T00:00:00Z"
    }
  }
  ```
</CodeGroup>

### Create an AI Interviewer

Set `interviewType: "ai_interviewer"` and provide an `aiConfiguration`. The persona is
generated server-side.

<CodeGroup>
  ```json Request theme={null}
  {
    "title": "AI Screen — Backend Engineer",
    "displayName": "AI Screen",
    "interviewType": "ai_interviewer",
    "language": "en",
    "aiTextQuestionIds": ["ai-text-question-uuid"],
    "jobDescriptionText": "We are hiring a senior backend engineer...",
    "knowledgeBaseIds": ["kb-uuid"],
    "scoreCardTopics": [
      {
        "topic": "System Design",
        "weight": 60,
        "lookingFor": ["Scalability", "Trade-off analysis"],
        "scoreDescriptions": {
          "level1": "Limited system design ability",
          "level3": "Adequate system design ability",
          "level5": "Exceptional system design ability"
        }
      }
    ],
    "aiConfiguration": {
      "replicaId": "replica-uuid",
      "friendlyTone": true,
      "professionalTone": true,
      "askFollowUpQuestions": true,
      "callRecording": true,
      "closedCaptions": true,
      "captureResponses": true,
      "language": "en",
      "timeoutSeconds": 1800
    }
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "interview": {
        "id": "interview-uuid",
        "title": "AI Screen — Backend Engineer",
        "displayName": "AI Screen",
        "interviewType": "ai_interviewer",
        "status": 0,
        "language": "en",
        "resume": false,
        "webOnly": false,
        "organizationId": "org-uuid",
        "teamId": "team-uuid",
        "createdById": "user-uuid",
        "createdAt": "2026-06-16T00:00:00Z",
        "updatedAt": "2026-06-16T00:00:00Z",
        "audioOnly": false,
        "replicaId": "replica-uuid",
        "aiConfiguration": {
          "askFollowUpQuestions": true,
          "askToElaborate": false,
          "digDeeper": false,
          "friendlyTone": true,
          "professionalTone": true,
          "conversationalStyle": true,
          "audioOnly": false,
          "greetingMessage": null,
          "closedCaptions": true,
          "callRecording": true,
          "captureResponses": true,
          "askCandidateQuestions": false,
          "language": "en",
          "timeoutSeconds": 1800,
          "coachingType": null,
          "coachingSubType": null,
          "conversationalContext": "Interview for AI Screen — Backend Engineer...",
          "replicaId": "replica-uuid",
          "replica": {
            "id": "replica-uuid",
            "name": "Avatar",
            "photoUrl": "https://example.com/avatar.png",
            "replicaId": "replica-ext-id"
          }
        }
      }
    },
    "meta": {
      "requestId": "req-uuid",
      "timestamp": "2026-06-16T00:00:00Z"
    }
  }
  ```
</CodeGroup>

<Callout type="info">
  For `ai_interviewer` interviews, `GET /qsi/gather/interviews/{interviewId}` and `PATCH`
  return the same nested `aiConfiguration` object (including the read-only
  `conversationalContext`). To update behavior, send an `aiConfiguration` on `PATCH` — the
  persona is regenerated automatically.
</Callout>

## Get Interview

Retrieve interview details including questions.

**Endpoint:** `GET /qsi/gather/interviews/{interviewId}`

<ParamField path="interviewId" type="string" required>
  UUID of the interview
</ParamField>

<ParamField query="teamId" type="string">
  Override the team context for this request
</ParamField>

<CodeGroup>
  ```json Response theme={null}
  {
    "data": {
      "interview": {
        "id": "interview-uuid",
        "title": "Software Engineer Interview",
        "displayName": "Software Engineer Interview",
        "interviewType": "standard",
        "status": 0,
        "description": "Technical interview for software engineering role",
        "descriptionUrl": "https://example.com/job-description",
        "language": "en",
        "resume": true,
        "webOnly": false,
        "messageGroupId": "msg-group-uuid",
        "narratorId": "narrator-uuid",
        "organizationId": "org-uuid",
        "teamId": "team-uuid",
        "createdById": "user-uuid",
        "createdAt": "2026-01-15T00:00:00Z",
        "updatedAt": "2026-01-15T00:00:00Z"
      }
    },
    "meta": {
      "requestId": "req-uuid",
      "timestamp": "2026-01-15T00:00:00Z"
    }
  }
  ```
</CodeGroup>

## List Interviews

List all interviews with pagination and filtering.

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

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

<ParamField query="pageSize" type="number">
  Items per page
</ParamField>

<ParamField query="search" type="string">
  Search interviews by title
</ParamField>

<ParamField query="archived" type="boolean">
  Include archived interviews (default: `false`)
</ParamField>

<ParamField query="interviewType" type="string">
  Filter by type: `"standard"` or `"questionnaire"`
</ParamField>

<CodeGroup>
  ```json Response theme={null}
  {
    "data": {
      "interviews": [
        {
          "id": "interview-uuid",
          "title": "Software Engineer Interview",
          "displayName": "Software Engineer Interview",
          "interviewType": "standard",
          "status": 0,
          "description": "Technical interview for software engineering role",
          "language": "en",
          "resume": false,
          "webOnly": false,
          "messageGroupId": "msg-group-uuid",
          "organizationId": "org-uuid",
          "teamId": "team-uuid",
          "createdById": "user-uuid",
          "createdAt": "2026-01-15T00:00:00Z",
          "updatedAt": "2026-01-15T00:00:00Z"
        }
      ],
      "pagination": {
        "total": 42,
        "page": 1,
        "pages": 5,
        "pageSize": 10
      }
    },
    "meta": {
      "requestId": "req-uuid",
      "timestamp": "2026-01-15T00:00:00Z"
    }
  }
  ```
</CodeGroup>

## Update Interview

Update interview properties including questions, keywords, and settings.

**Endpoint:** `PATCH /qsi/gather/interviews/{interviewId}`

<ParamField path="interviewId" type="string" required>
  UUID of the interview to update
</ParamField>

<ParamField name="title" type="string">
  Updated title
</ParamField>

<ParamField name="displayName" type="string">
  Updated display name
</ParamField>

<ParamField name="description" type="string">
  Updated description
</ParamField>

<ParamField name="descriptionUrl" type="string">
  URL to a job description
</ParamField>

<ParamField name="descriptionFileName" type="string">
  File name for the job description attachment
</ParamField>

<ParamField name="language" type="string">
  Language code (e.g., `"en"`, `"es"`)
</ParamField>

<ParamField name="resume" type="boolean">
  Whether resume is required
</ParamField>

<ParamField name="webOnly" type="boolean">
  Web-only interview
</ParamField>

<ParamField name="questionIds" type="string[]">
  Updated array of question UUIDs (replaces existing questions)
</ParamField>

<ParamField name="surveyQuestions" type="object[]">
  Array of survey question objects. Each object contains:

  * `id` (string) — UUID of the survey question
  * `knockout` (boolean) — whether the question is a knockout question
</ParamField>

<ParamField name="messageGroupId" type="string">
  UUID of message group
</ParamField>

<ParamField name="narratorId" type="string">
  UUID of narrator for TTS
</ParamField>

<ParamField name="keywords" type="string[]">
  Array of keyword strings to add
</ParamField>

<ParamField name="removedKeywords" type="string[]">
  Array of keyword strings to remove
</ParamField>

<ParamField name="notificationSubscribers" type="string[]">
  Array of user UUIDs to receive notifications
</ParamField>

<ParamField name="audioMessageId" type="string">
  UUID of an existing audio message
</ParamField>

<ParamField name="audioMessageURL" type="string">
  URL of a custom audio message
</ParamField>

<ParamField name="audioMessageTitle" type="string">
  Title for the custom audio message
</ParamField>

<CodeGroup>
  ```json Request theme={null}
  {
    "title": "Updated Interview Title",
    "questionIds": ["uuid1", "uuid2", "uuid3"],
    "surveyQuestions": [
      { "id": "survey-q-uuid", "knockout": true }
    ],
    "keywords": ["python", "django"],
    "removedKeywords": ["php"]
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "interview": {
        "id": "interview-uuid",
        "title": "Updated Interview Title",
        "displayName": "Software Engineer Interview",
        "interviewType": "standard",
        "status": 0,
        "description": "Technical interview for software engineering role",
        "language": "en",
        "resume": false,
        "webOnly": false,
        "messageGroupId": "msg-group-uuid",
        "narratorId": "narrator-uuid",
        "organizationId": "org-uuid",
        "teamId": "team-uuid",
        "createdById": "user-uuid",
        "createdAt": "2026-01-15T00:00:00Z",
        "updatedAt": "2026-01-16T00:00:00Z"
      }
    },
    "meta": {
      "requestId": "req-uuid",
      "timestamp": "2026-01-16T00:00:00Z"
    }
  }
  ```
</CodeGroup>

## Delete Interview

Archive an interview.

**Endpoint:** `DELETE /qsi/gather/interviews/{interviewId}`

<ParamField path="interviewId" type="string" required>
  UUID of the interview to archive
</ParamField>

<ParamField query="teamId" type="string">
  Override the team context for this request
</ParamField>

<ParamField query="userId" type="string">
  User performing the archive action
</ParamField>

<CodeGroup>
  ```json Response theme={null}
  {
    "data": {
      "interview": {
        "id": "interview-uuid",
        "title": "Software Engineer Interview",
        "displayName": "Software Engineer Interview",
        "interviewType": "standard",
        "status": 3,
        "language": "en",
        "resume": false,
        "webOnly": false,
        "organizationId": "org-uuid",
        "teamId": "team-uuid",
        "createdById": "user-uuid",
        "createdAt": "2026-01-15T00:00:00Z",
        "updatedAt": "2026-02-01T00:00:00Z",
        "archivedAt": "2026-02-01T00:00:00Z"
      }
    },
    "meta": {
      "requestId": "req-uuid",
      "timestamp": "2026-02-01T00:00:00Z"
    }
  }
  ```
</CodeGroup>

## Copy Interview

Copy an interview template to a different team (or the same team with a "(copy)" suffix). The copied interview includes all questions, survey questions, AI text questions, keywords (optional), score card templates, and AI interview configurations.

**Endpoint:** `POST /qsi/gather/interviews/{interviewId}/copy`

<ParamField path="interviewId" type="string" required>
  UUID of the interview to copy
</ParamField>

<ParamField name="teamId" type="string" required>
  UUID of the target team
</ParamField>

<ParamField name="copyKeywords" type="boolean">
  Whether to copy keywords (default: false)
</ParamField>

<ParamField name="messageGroupId" type="string">
  UUID of message group to use (uses default if not provided)
</ParamField>

<Tabs>
  <Tab title="cURL">
    ```bash theme={null}
    curl -X POST https://api.prod.qualifi.hr/qsi/gather/interviews/{interviewId}/copy \
      -H "x-api-key: ${API_KEY}" \
      -H "Content-Type: application/json" \
      -d '{
        "teamId": "target-team-uuid",
        "copyKeywords": false
      }'
    ```
  </Tab>

  <Tab title="JavaScript">
    ```javascript theme={null}
    const response = await fetch(
      `https://api.prod.qualifi.hr/qsi/gather/interviews/${interviewId}/copy`,
      {
        method: 'POST',
        headers: {
          'x-api-key': apiKey,
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          teamId: 'target-team-uuid',
          copyKeywords: false
        })
      }
    );
    const interview = await response.json();
    ```
  </Tab>

  <Tab title="Python">
    ```python theme={null}
    response = requests.post(
        f'https://api.prod.qualifi.hr/qsi/gather/interviews/{interview_id}/copy',
        headers={
            'x-api-key': api_key,
            'Content-Type': 'application/json'
        },
        json={
            'teamId': 'target-team-uuid',
            'copyKeywords': False
        }
    )
    interview = response.json()
    ```
  </Tab>
</Tabs>

<CodeGroup>
  ```json Request theme={null}
  {
    "teamId": "target-team-uuid",
    "copyKeywords": false,
    "messageGroupId": "message-group-uuid"
  }
  ```

  ```json Response theme={null}
  {
    "data": {
      "interview": {
        "id": "copied-interview-uuid",
        "title": "Engineering Interview",
        "displayName": "Engineering Interview",
        "interviewType": "standard",
        "status": 0,
        "description": "Interview for engineering candidates",
        "language": "en",
        "resume": true,
        "webOnly": false,
        "messageGroupId": "message-group-uuid",
        "organizationId": "org-uuid",
        "teamId": "target-team-uuid",
        "createdById": "user-uuid",
        "createdAt": "2026-01-15T00:00:00Z",
        "updatedAt": "2026-01-15T00:00:00Z"
      }
    },
    "meta": {
      "requestId": "req-uuid",
      "timestamp": "2026-01-15T00:00:00Z"
    }
  }
  ```
</CodeGroup>

### Copy Behavior

**Questions:**

* **Different Team**: Questions are copied as new questions in the target team
* **Same Team**: Questions are reused (not duplicated)

**Survey Questions:**

* **Different Team**: Survey questions are copied with all options and preferred options
* **Same Team**: Survey questions are reused

**AI Text Questions:**

* **Different Team**: AI text questions are copied as new questions
* **Same Team**: AI text questions are reused

**Keywords:**

* Only copied if `copyKeywords: true`
* Creates new keyword associations for the copied interview

**Score Card Templates:**

* All score card templates are copied to the new interview

**AI Interview Configuration:**

* For AI interviews, a new AI interviewer persona is created
* AI configuration is copied with the new persona ID
* Original persona is not modified

**MessageGroup:**

* If `messageGroupId` is provided, it will be used
* If not provided, the default message group for the interview type will be used

<Callout type="info">
  When copying to the same team, the interview title will automatically have
  "(copy)" appended to avoid conflicts.
</Callout>

## Interview Types

### Standard Interviews

Standard interviews use audio questions that are played to candidates during phone calls.

### Questionnaire Interviews

Questionnaire interviews use survey questions that candidates answer via web interface.

<Callout type="info">
  You can mix question types in standard interviews, but questionnaire-type
  interviews are specifically designed for survey-style questions.
</Callout>

## Related Resources

<CardGroup cols={2}>
  <Card title="Questions" icon="file-text" href="/api-reference/questions">
    Learn about creating questions for interviews
  </Card>

  <Card title="Candidate Interviews" icon="user" href="/api-reference/candidate-interviews">
    Send interview invites to candidates
  </Card>

  <Card title="Bulk Update Interviews" icon="layers" href="/api-reference/interviews-bulk-update">
    Update multiple interviews in a single request
  </Card>
</CardGroup>
