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

# How-to: Fetching Interview Transcriptions

## When to use this

Use this query when you want to retrieve the **video transcriptions** for a candidate's interview answers — for example, to display transcripts in your own hiring dashboard, feed them into an AI screening tool, or search across candidate responses by keyword.

Each interview has one or more `stepExecutions` (one per interview question), and each step can carry a transcription of the candidate's video answer.

## GraphQL Request

Use this query to fetch the transcription for every step in an interview. Don't forget to replace the `id` with the interview you want to fetch, and update the [Hireflix API Key](/tech/quickstart) in the `headers`.

<iframe src="https://cdn.hireflix.com/graphql-playground/index.html?query=GetInterviewTranscriptions&url=https://api.hireflix.com/me" width="100%" height="750" />

### Explanation

* **id** – the ID of the interview you want to fetch transcriptions for.
* **stepExecutions** – one entry per interview question. Each step is typed as `AdminInterviewStepQAExecution`.
* **latestAnswer** – the candidate's most recent answer for that step. Typed as `InterviewStepQAVideoAnswer` for video responses.
* **transcription** – contains the transcribed `text`, the `languageCode` it was detected in, and `vttSubtitles` (WebVTT-formatted captions, useful if you want to render a subtitled video player).

### Example Response

```json theme={null}
{
  "data": {
    "interview": {
      "id": "6a79c65ae26008ae3df7b50e",
      "stepExecutions": [
        {
          "id": "6a79c65ae26008ae3df7b50c",
          "finishedAt": "2026-08-10T12:39:30.596Z",
          "status": "COMPLETED",
          "latestAnswer": {
            "video": {
              "transcription": {
                "languageCode": "en",
                "text": "Hey. I would really like to join this company because it's one of the coolest companies out there in the AI space, and it would really suit my skill set...",
                "vttSubtitles": "WEBVTT\n\n00:01.200 --> 00:03.920\nHey. I would really like to join this company because...\n"
              }
            }
          }
        },
        {
          "id": "6a79c65ae26008ae3df7b50d",
          "finishedAt": "2026-08-10T12:40:04.158Z",
          "status": "COMPLETED",
          "latestAnswer": {
            "video": {
              "transcription": null
            }
          }
        }
      ]
    }
  }
}
```

<Warning>
  `transcription` can return `null` even for a **completed** step with a valid video answer — as shown in the second step above. This usually means transcription is still processing or wasn't available for that answer. Always check for `null` before reading `transcription.text` in your code.
</Warning>

### Tips

* **Flatten the response client-side.** GraphQL mirrors your query's shape — it won't merge or restructure the array for you. A small helper function makes the response easier to work with:

  <CodeGroup>
    ```javascript flatten.js theme={null}
    function flattenTranscriptions(interview) {
      return interview.stepExecutions
        .filter(step => step.latestAnswer?.video?.transcription)
        .map(step => ({
          stepId: step.id,
          finishedAt: step.finishedAt,
          language: step.latestAnswer.video.transcription.languageCode,
          text: step.latestAnswer.video.transcription.text,
          vtt: step.latestAnswer.video.transcription.vttSubtitles,
        }));
    }
    ```

    ```python flatten.py theme={null}
    def flatten_transcriptions(interview):
        result = []
        for step in interview.get("stepExecutions", []):
            video = (step.get("latestAnswer") or {}).get("video") or {}
            transcription = video.get("transcription")
            if transcription:
                result.append({
                    "stepId": step.get("id"),
                    "finishedAt": step.get("finishedAt"),
                    "language": transcription.get("languageCode"),
                    "text": transcription.get("text"),
                    "vtt": transcription.get("vttSubtitles"),
                })
        return result
    ```

    ```go flatten.go theme={null}
    type Transcription struct {
        LanguageCode string `json:"languageCode"`
        Text         string `json:"text"`
        VTTSubtitles string `json:"vttSubtitles"`
    }

    type Video struct {
        Transcription *Transcription `json:"transcription"`
    }

    type LatestAnswer struct {
        Video *Video `json:"video"`
    }

    type StepExecution struct {
        ID           string        `json:"id"`
        FinishedAt   string        `json:"finishedAt"`
        LatestAnswer *LatestAnswer `json:"latestAnswer"`
    }

    type Interview struct {
        ID             string          `json:"id"`
        StepExecutions []StepExecution `json:"stepExecutions"`
    }

    type FlatTranscription struct {
        StepID     string `json:"stepId"`
        FinishedAt string `json:"finishedAt"`
        Language   string `json:"language"`
        Text       string `json:"text"`
        VTT        string `json:"vtt"`
    }

    func FlattenTranscriptions(interview Interview) []FlatTranscription {
        var result []FlatTranscription
        for _, step := range interview.StepExecutions {
            if step.LatestAnswer == nil || step.LatestAnswer.Video == nil || step.LatestAnswer.Video.Transcription == nil {
                continue
            }
            t := step.LatestAnswer.Video.Transcription
            result = append(result, FlatTranscription{
                StepID:     step.ID,
                FinishedAt: step.FinishedAt,
                Language:   t.LanguageCode,
                Text:       t.Text,
                VTT:        t.VTTSubtitles,
            })
        }
        return result
    }
    ```
  </CodeGroup>

* **Handle missing transcriptions gracefully.** Don't assume every completed step has one — build in a fallback (e.g. "Transcript pending" or a retry check) rather than letting your UI break on `null`.

* **Use `id` on each step** to correlate a transcription back to the specific interview question it belongs to, especially if you're storing transcripts against your own question records.

<Accordion title="✅ FAQ: Why is transcription null on a completed step?">
  A `COMPLETED` step means the candidate submitted their video answer — it doesn't guarantee the transcription has finished processing yet. Transcription happens asynchronously after the video is uploaded. If you consistently see `null` for older, fully processed interviews, check with Hireflix support, since it may indicate the transcription failed for that specific answer rather than being pending.
</Accordion>

<Card color="#5863ff" icon="arrow-right" horizontal href="/tech/features/interviews/scoring-and-commenting-interviews" title="Learn next?">
  Let's learn how to score and comment on interviews.
</Card>
