Skip to main content

Endpoint

GET /api/interview/sessions/{sessionId}/export
Exports the interview evaluation report as a professionally formatted PDF document. The PDF includes all questions, answers, scores, feedback, reference answers, and improvement suggestions in a readable format suitable for printing or sharing.
The report must be generated first using the Get Report endpoint before exporting. The PDF export uses the evaluation data from the generated report.

Path Parameters

sessionId
string
required
The unique session identifier for the completed and evaluated interview session.

Response

This endpoint returns a binary PDF file with appropriate headers for browser download.
Content-Type
header
application/pdf - Indicates the response is a PDF file.
Content-Disposition
header
attachment; filename*=UTF-8''模拟面试报告_{sessionId}.pdf - Instructs the browser to download the file with a localized filename.
Body
binary
The PDF file bytes containing the formatted interview report.

Example Request

curl -O -J https://api.example.com/api/interview/sessions/a1b2c3d4-e5f6-4789-g0h1-i2j3k4l5m6n7/export
Use the -O flag to save the file and -J to use the server-specified filename from the Content-Disposition header.

Example with JavaScript

async function downloadReport(sessionId) {
  const response = await fetch(
    `/api/interview/sessions/${sessionId}/export`
  );
  
  if (!response.ok) {
    throw new Error('Failed to download report');
  }
  
  // Get the blob data
  const blob = await response.blob();
  
  // Extract filename from Content-Disposition header
  const contentDisposition = response.headers.get('Content-Disposition');
  const filenameMatch = contentDisposition.match(/filename\*=UTF-8''(.+)/);
  const filename = filenameMatch 
    ? decodeURIComponent(filenameMatch[1]) 
    : `interview-report-${sessionId}.pdf`;
  
  // Create download link
  const url = window.URL.createObjectURL(blob);
  const a = document.createElement('a');
  a.href = url;
  a.download = filename;
  document.body.appendChild(a);
  a.click();
  
  // Cleanup
  window.URL.revokeObjectURL(url);
  document.body.removeChild(a);
}

// Usage
try {
  await downloadReport('a1b2c3d4-e5f6-4789-g0h1-i2j3k4l5m6n7');
  console.log('Report downloaded successfully');
} catch (error) {
  console.error('Download failed:', error);
}

PDF Report Contents

The exported PDF includes the following sections:
1

Cover Page

Session information, candidate details, interview date, and overall score with visual indicator.
2

Summary

Overall feedback, total score, category breakdown chart, strengths, and improvement areas.
3

Category Analysis

Detailed scores for each technical category (Java, Spring, MySQL, Redis, etc.) with visual charts.
4

Question-by-Question Details

Each question with:
  • Question text and category
  • Candidate’s answer
  • Individual score
  • AI feedback
  • Reference answer
  • Key points to cover
5

Improvement Plan

Specific, actionable recommendations for skill development and learning resources.
6

Footer

Page numbers, session ID, and generation timestamp.

Use Cases

Candidate Review

Candidates can download their report to review feedback and plan improvements.

Hiring Records

Interviewers can save reports as part of the hiring process documentation.

Performance Tracking

Track progress by comparing reports from multiple interview sessions over time.

Sharing

Share professionally formatted reports with team members or mentors.

Error Responses

Unlike other endpoints, this endpoint returns standard HTTP error responses without JSON wrapping.

HTTP Status Codes

CodeStatusDescription
200OKPDF generated and returned successfully
404Not FoundSession ID does not exist
400Bad RequestReport not yet generated for this session
500Internal Server ErrorPDF generation failed

Error Response Body

For errors, the response body may be empty or contain a brief error message. The HTTP status code is the primary error indicator.
# Example 404 response
HTTP/1.1 404 Not Found
Content-Length: 0

Get Report

Generate the evaluation report data (required before export)

Get Session

Check session status before exporting

Delete Session

Remove session after exporting report

Submit Answer

Answer interview questions

Best Practices

Always generate the report using GET /report before attempting to export:
// 1. Generate report
await fetch(`/api/interview/sessions/${sessionId}/report`);

// 2. Then export PDF
await downloadReport(sessionId);
PDF reports can be several MB depending on content. Show progress indicators:
async function downloadReportWithProgress(sessionId) {
  const response = await fetch(
    `/api/interview/sessions/${sessionId}/export`
  );
  
  const contentLength = response.headers.get('Content-Length');
  const total = parseInt(contentLength, 10);
  let loaded = 0;
  
  const reader = response.body.getReader();
  const chunks = [];
  
  while (true) {
    const { done, value } = await reader.read();
    if (done) break;
    
    chunks.push(value);
    loaded += value.length;
    
    const progress = (loaded / total) * 100;
    updateProgressBar(progress);
  }
  
  const blob = new Blob(chunks, { type: 'application/pdf' });
  saveBlob(blob, `interview-report-${sessionId}.pdf`);
}
Provide clear error messages and recovery options:
try {
  await downloadReport(sessionId);
} catch (error) {
  if (error.status === 404) {
    showError('Session not found. Please check the session ID.');
  } else if (error.status === 400) {
    showError('Report not generated yet. Generating now...');
    await generateReport(sessionId);
    await downloadReport(sessionId);
  } else {
    showError('Download failed. Please try again.');
  }
}
Handle different filename encodings properly:
function extractFilename(contentDisposition) {
  // Try UTF-8 encoded filename first
  let match = contentDisposition.match(/filename\*=UTF-8''(.+)/);
  if (match) {
    return decodeURIComponent(match[1]);
  }
  
  // Fallback to standard filename
  match = contentDisposition.match(/filename="?(.+?)"?$/);
  return match ? match[1] : 'interview-report.pdf';
}
Handle mobile browsers that may not support direct downloads:
async function downloadReportMobile(sessionId) {
  const response = await fetch(
    `/api/interview/sessions/${sessionId}/export`
  );
  const blob = await response.blob();
  
  // For mobile, open in new tab
  if (isMobile()) {
    const url = URL.createObjectURL(blob);
    window.open(url, '_blank');
    setTimeout(() => URL.revokeObjectURL(url), 60000);
  } else {
    // Desktop: trigger download
    saveBlob(blob, `report-${sessionId}.pdf`);
  }
}

PDF Report Features

The generated PDF includes:
  • Professional Formatting: Clean layout with proper typography and spacing
  • Visual Elements: Charts and graphs for score visualization
  • Color Coding: Color-coded scores (green for excellent, yellow for adequate, red for needs improvement)
  • Bilingual Support: Chinese content with proper character encoding
  • Print Optimization: Formatted for A4 paper size with appropriate margins
  • Metadata: Embedded PDF metadata including title, author, and creation date
The PDF filename includes Chinese characters (模拟面试报告) followed by the session ID. Browsers that support RFC 5987 encoding will display the Chinese characters correctly.

Implementation Example

Complete React component for downloading reports:
import { useState } from 'react';
import { Button, Progress, Alert } from '@/components/ui';

function ReportExportButton({ sessionId }) {
  const [loading, setLoading] = useState(false);
  const [error, setError] = useState(null);
  const [progress, setProgress] = useState(0);
  
  const handleExport = async () => {
    setLoading(true);
    setError(null);
    setProgress(0);
    
    try {
      const response = await fetch(
        `/api/interview/sessions/${sessionId}/export`
      );
      
      if (!response.ok) {
        if (response.status === 400) {
          // Report not generated, generate it first
          await fetch(`/api/interview/sessions/${sessionId}/report`);
          // Retry export
          return handleExport();
        }
        throw new Error('Export failed');
      }
      
      // Download with progress
      const contentLength = response.headers.get('Content-Length');
      const total = parseInt(contentLength, 10);
      let loaded = 0;
      
      const reader = response.body.getReader();
      const chunks = [];
      
      while (true) {
        const { done, value } = await reader.read();
        if (done) break;
        
        chunks.push(value);
        loaded += value.length;
        setProgress((loaded / total) * 100);
      }
      
      // Create blob and trigger download
      const blob = new Blob(chunks, { type: 'application/pdf' });
      const url = URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `interview-report-${sessionId}.pdf`;
      document.body.appendChild(a);
      a.click();
      
      // Cleanup
      URL.revokeObjectURL(url);
      document.body.removeChild(a);
      
    } catch (err) {
      setError(err.message);
    } finally {
      setLoading(false);
      setProgress(0);
    }
  };
  
  return (
    <div className="space-y-2">
      <Button 
        onClick={handleExport} 
        disabled={loading}
        className="w-full"
      >
        {loading ? 'Downloading...' : 'Download PDF Report'}
      </Button>
      
      {loading && <Progress value={progress} />}
      {error && <Alert variant="error">{error}</Alert>}
    </div>
  );
}

export default ReportExportButton;
After downloading the report, consider offering the option to delete the session if the user no longer needs it stored in the system.

Build docs developers (and LLMs) love