Skip to main content
POST
/
interviews
Create interview
curl --request POST \
  --url https://api.instaview.sk/interviews \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "candidateId": "123e4567-e89b-12d3-a456-426614174000",
  "jobId": "123e4567-e89b-12d3-a456-426614174000",
  "agentId": "987e6543-e21b-12d3-a456-426614174000",
  "scheduleTime": "2025-11-20T10:00:00Z",
  "job": {
    "title": "Senior TypeScript Developer",
    "description": "We are looking for an experienced TypeScript developer...",
    "jobUrl": "https://company.com/careers/senior-typescript-dev",
    "benefits": "Health insurance, remote work, flexible hours",
    "requiredSkills": [
      "TypeScript",
      "React",
      "Node.js"
    ],
    "niceToHaveSkills": [
      "Docker",
      "AWS",
      "GraphQL"
    ],
    "languageRequirements": [
      {
        "language": "EN",
        "proficiency": "B2"
      },
      {
        "language": "SK",
        "proficiency": "C1"
      }
    ],
    "education": [
      "BACHELOR_LEVEL",
      "MASTER_LEVEL"
    ],
    "experience": "FIVE_TO_10_YEARS",
    "contractType": "FULL_TIME",
    "status": "OPEN",
    "location": {
      "workMode": "REMOTE",
      "street": "Hlavná 123",
      "city": "Bratislava",
      "postalCode": "81101",
      "countryCode": "SK"
    },
    "salary": {
      "min": 50000,
      "max": 80000,
      "currency": "USD",
      "period": "YEARLY"
    },
    "metadata": {
      "externalJobId": "JOB-12345",
      "department": "Engineering",
      "hiringManager": "Jane Doe"
    }
  },
  "candidate": {
    "firstName": "John",
    "lastName": "Doe",
    "gdprExpiryDate": "2026-11-16",
    "email": "[email protected]",
    "phoneNumber": "+421915123456",
    "jobId": "123e4567-e89b-12d3-a456-426614174000"
  },
  "agent": {
    "type": "ONLINE",
    "name": "Senior Developer Interview",
    "focus": "SCREENING",
    "language": "EN",
    "duration": 30,
    "companyPhoneNumberId": "123e4567-e89b-12d3-a456-426614174000",
    "questions": [
      "What is your experience with React?",
      "Tell me about a challenging project you worked on"
    ],
    "instructions": "Focus on technical skills and previous project experience",
    "voiceId": "ALEX",
    "cefrLevel": "B1"
  },
  "metadata": {
    "externalInterviewId": "INT-789",
    "interviewerNotes": "Focus on technical skills"
  },
  "isTest": false
}
'
{
"id": "123e4567-e89b-12d3-a456-426614174000",
"candidateId": "987e6543-e21b-12d3-a456-426614174000",
"agentId": "456e7890-e12b-34d5-a678-901234567890",
"status": "SCHEDULED",
"scheduledAt": "2025-11-20T10:00:00Z",
"createdAt": "2024-11-16T10:30:00Z",
"updatedAt": "2024-11-16T10:30:00Z",
"jobId": "123e4567-e89b-12d3-a456-426614174000",
"durationMinutes": 15,
"finishedDate": "2025-11-20T10:15:00Z",
"metadata": {
"externalInterviewId": "INT-789"
},
"callAttempts": [
{
"id": "c9c9a6e8-fb4a-45f3-80fc-bf94f071cd2a",
"direction": "OUTBOUND",
"status": "COMPLETED",
"reasonCode": "NO_ANSWER",
"notes": "Candidate did not pick up, mailbox full",
"retryNumber": 2,
"recordingUrl": "https://audio.example.com/recording.mp3",
"duration": 180,
"scheduledAt": "2025-07-22T10:00:00Z",
"calledAt": "2025-07-22T10:01:00Z"
}
],
"analysis": {
"id": "123e4567-e89b-12d3-a456-426614174000",
"general": {
"createdAt": "2024-11-16T10:30:00Z",
"updatedAt": "2024-11-16T10:30:00Z",
"overallRating": 85,
"companyFitRating": "HIGH",
"education": "Master's degree in Computer Science",
"experience": "5 years of experience in software development",
"strongPoints": [
"Excellent communication skills",
"Strong technical expertise in React and Node.js",
"Proven track record of leading teams"
],
"weakPoints": [
"Limited experience with microservices",
"Needs improvement in system design"
],
"evaluation": [
"Strong candidate with relevant experience",
"Good cultural fit for the team",
"Recommended for next round"
],
"status": 3
},
"specific": {
"pronunciationScores": {
"accuracy": 90,
"fluency": 85
},
"grammar": {
"level": "C1"
}
}
},
"isTest": false
}
Creates a new AI-powered interview session for a candidate. This endpoint supports both existing candidates/agents and inline resource creation, making it flexible for various integration scenarios.

Overview

The create interview endpoint allows you to schedule AI-powered interviews with candidates. You can use existing candidate and agent IDs, or create them on-the-fly using inline definitions. Interviews can be scheduled for a future time or started immediately.

Use Cases

  • Scheduled Interviews: Schedule interviews for a specific date and time
  • Immediate Interviews: Start interviews right away for quick screening
  • Inline Resources: Create interviews without pre-creating candidates or agents
  • Bulk Interview Scheduling: Automate interview scheduling for multiple candidates

Inline Candidate, Agent, and Job Support

You can create interviews with candidates, agents, and jobs that don’t exist yet by providing inline resource objects. This enables streamlined interview scheduling without pre-creating resources in your system.

Inline Candidate with Job Association

{
  "candidate": {
    "jobId": "job-uuid",
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "[email protected]",
    "phoneNumber": "+1234567890",
    "gdprExpiryDate": "2026-11-16"
  },
  "agentId": "existing-agent-uuid",
  "scheduleTime": "2024-01-20T14:00:00Z"
}

Inline Candidate with Inline Job

Create both the candidate and job inline for a completely self-contained interview creation:
{
  "candidate": {
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "[email protected]",
    "phoneNumber": "+1234567890",
    "gdprExpiryDate": "2026-11-16"
  },
  "job": {
    "jobTitle": "Senior Backend Engineer",
    "jobDescription": "We are looking for a senior engineer...",
    "requiredSkills": ["TypeScript", "NestJS", "PostgreSQL"],
    "niceToHaveSkills": ["Redis", "AWS"],
    "languages": ["EN"],
    "experience": "SENIOR",
    "contractType": "FULL_TIME"
  },
  "agentId": "existing-agent-uuid",
  "scheduleTime": "2024-01-20T14:00:00Z"
}
Complete Inline Workflow: When using candidate with job: - A new Job entity is created in your company - A new Candidate entity is created and automatically associated with the new job
  • The Interview is linked to both the new candidate and job - All resources become permanent entities in your system - This is the most streamlined way to schedule interviews without any pre-existing resources

Inline Candidate without Job Association

{
  "candidate": {
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "[email protected]",
    "phoneNumber": "+1234567890",
    "gdprExpiryDate": "2026-11-16"
  },
  "agentId": "existing-agent-uuid",
  "scheduleTime": "2024-01-20T14:00:00Z"
}
Job Specification Options: You can specify the job in several ways: - Create inline: Use job at the DTO level to create a new job - Reference existing: Use jobId at the DTO level to link to an existing job - Within inline candidate: Use jobId inside candidate for a more compact syntax when creating both candidate and job association - No job: Omit all job fields to create a candidate in your talent pool without job association (can be assigned later via the update candidate endpoint) Priority: When multiple job sources are provided, job takes precedence over DTO-level jobId, which takes precedence over candidate.jobId. XOR Validation: You cannot combine candidate.jobId with DTO-level job fields (jobId or job) as this would be ambiguous. Choose one method per request.

Generic Focus and Jobless Interviews

GENERIC Focus Requirement: When using an agent with focus: "GENERIC", the candidate must NOT have any job assignments. This is required for jobless interviews.
Generic focus agents are designed for interviews where candidates don’t need to be assigned to a specific job. This is useful for:
  • Talent Pool Building: Interviewing candidates for future opportunities without a specific role
  • General Outreach: Engaging with candidates in your database who aren’t currently assigned to jobs
  • Pre-screening: Conducting initial conversations before matching candidates to specific positions

Creating a Jobless Interview with GENERIC Focus

{
  "candidate": {
    "firstName": "Jane",
    "lastName": "Doe",
    "email": "[email protected]",
    "phoneNumber": "+1234567890",
    "gdprExpiryDate": "2026-11-16"
    // No jobId - candidate has no job assignments
  },
  "agentId": "generic-agent-uuid", // Agent with focus: "GENERIC"
  "scheduleTime": "2024-01-20T14:00:00Z"
}
Validation: The API will return a 400 Bad Request error if:
  • You use a GENERIC focus agent with a candidate that has job assignments
  • You try to create a jobless interview (no job specified) with a non-GENERIC agent
For more details on Generic interview analysis structure, see the Interviews Resource Guide.

Existing Candidate with Inline Job

You can also define the job inline using job when you already have a candidate but don’t want to create a separate job resource first.
{
  "candidateId": "candidate-uuid",
  "job": {
    "jobTitle": "Senior Backend Engineer",
    "jobDescription": "We are looking for a senior engineer...",
    "jobUrl": "https://company.com/jobs/123",
    "benefits": "Health insurance, remote work",
    "requiredSkills": ["TypeScript", "NestJS", "PostgreSQL"],
    "niceToHaveSkills": ["Redis", "AWS"],
    "languages": ["EN"],
    "languageRequirements": [
      { "language": "EN", "proficiency": "C1" }
    ],
    "education": ["BACHELORS"],
    "experience": "SENIOR",
    "otherRequirements": "Comfortable with async communication",
    "contractType": "FULL_TIME",
    "location": {
      "workMode": "REMOTE",
      "street": "Main Street 1",
      "city": "Bratislava",
      "postalCode": "81101",
      "countryCode": "SK"
    },
    "salary": {
      "min": 4000,
      "max": 5500,
      "currency": "EUR",
      "period": "MONTHLY"
    },
    "humanRecruiter": "John Doe",
    "metadata": {
      "externalJobId": "JOB-12345",
      "department": "Engineering"
    }
  },
  "agentId": "existing-agent-uuid",
  "scheduleTime": "2024-01-20T14:00:00Z"
}
Inline Job Behavior: - When you provide job together with an existing candidateId, the API: - Creates a full Job entity in your company using the inline fields. - Automatically associates the candidate with the new job if they weren’t already linked. - Links the interview to this newly created job. - jobId and job are mutually exclusive (XOR): - Use either jobId (existing job) or job (inline job definition), but not both.

Billing and Limits

Creating interviews consumes interview minutes from your company’s billing plan. Ensure you have sufficient minutes available before scheduling bulk interviews. The API will return a 403 Forbidden error if billing limits are exceeded.Exception: Test interviews (created with isTest: true) do not consume billing minutes and bypass all billing checks.

Scheduling Options

Immediate Interview

Omit scheduleTime to start the interview immediately:
{
  "candidateId": "candidate-uuid",
  "agentId": "agent-uuid"
}

Scheduled Interview

Provide a future scheduleTime timestamp (max 30 days in the future):
{
  "candidateId": "candidate-uuid",
  "agentId": "agent-uuid",
  "scheduleTime": "2024-01-20T14:00:00Z"
}
Note: When using existing candidates, ensure they already exist in your system. For inline candidates, all required fields (firstName, lastName, email or phoneNumber, gdprExpiryDate) must be provided.

Job Selection for Existing Candidates

When using an existing candidateId, you can optionally specify a jobId to indicate which job the interview is for. This is especially important when a candidate is associated with multiple jobs.

Candidate with Single Job

If the candidate has only one job (or no jobs), the jobId field is optional. The system will automatically use the candidate’s first job if available:
{
  "candidateId": "candidate-uuid",
  "agentId": "agent-uuid",
  "scheduleTime": "2024-01-20T14:00:00Z"
  // jobId is optional - system uses candidate's first job
}

Candidate with Multiple Jobs

When a candidate is associated with multiple jobs, you must specify the jobId to indicate which job the interview is for:
{
  "candidateId": "candidate-uuid",
  "jobId": "job-uuid",  // Required when candidate has multiple jobs
  "agentId": "agent-uuid",
  "scheduleTime": "2024-01-20T14:00:00Z"
}
Multiple Job Assignments: If a candidate has multiple job assignments and you don’t provide jobId, the API will return a 400 Bad Request error with the message “Job ID must be provided when candidate has multiple job assignments”.
Job Validation: The jobId you provide must: - Exist in the candidate’s job_ids array - Belong to the same company as your API key If the jobId doesn’t meet these requirements, the API will return a 400 Bad Request or 403 Forbidden error.
Job Selection Rules: - jobId and job are XOR (mutually exclusive): - If you provide jobId, you must omit job. - If you provide job, you must omit jobId. - When job is used: - A new job is created for your company. - That job is used as the interview’s jobId. - The candidate is associated with that job automatically before the interview is created.

Company Isolation

All resources (candidate, agent, job) must belong to the same company as your API key. The API automatically validates company ownership and returns 403 Forbidden if resources belong to different companies.

Complete Workflow Examples

Scenario 1: Interview with Job Association

// 1. Create a job (if not exists)
const job = await createJob({
  title: "Senior Software Engineer",
  status: "OPEN",
});

// 2. Create interview with inline candidate linked to job
const interview = await createInterview({
  candidate: {
    jobId: job.id,
    firstName: "Jane",
    lastName: "Doe",
    email: "[email protected]",
    phoneNumber: "+1234567890",
    gdprExpiryDate: "2026-11-16",
  },
  agentId: "agent-uuid",
  scheduleTime: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(), // Tomorrow
});

// 3. Monitor interview status
const status = await getInterview(interview.id);
console.log(`Interview status: ${status.status}`);

Scenario 2: Interview without Job Association (Talent Pool)

// 1. Create interview for candidate in talent pool (no job specified)
const interview = await createInterview({
  candidate: {
    firstName: "John",
    lastName: "Smith",
    email: "[email protected]",
    phoneNumber: "+1234567890",
    gdprExpiryDate: "2026-11-16",
  },
  agentId: "agent-uuid",
  scheduleTime: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
});

// 2. Later, assign candidate to specific job(s) if needed
const candidateId = interview.candidateId;
await updateCandidate(candidateId, {
  jobIds: ["job-uuid-1", "job-uuid-2"],
});

Scenario 3: Interview for Candidate with Multiple Jobs

// 1. Candidate is associated with multiple jobs
const candidate = await getCandidate("candidate-uuid");
// candidate.jobIds = ["job-1-uuid", "job-2-uuid", "job-3-uuid"]

// 2. Create interview for a specific job (jobId is required)
const interview = await createInterview({
  candidateId: "candidate-uuid",
  jobId: "job-2-uuid", // Must specify which job
  agentId: "agent-uuid",
  scheduleTime: "2024-01-20T14:00:00Z",
});

// 3. Interview is now associated with job-2-uuid
console.log(`Interview created for job: ${interview.jobId}`);

Scenario 4: Existing Candidate with Inline Job

// 1. Candidate already exists in your system
const candidateId = "candidate-uuid";

// 2. Create interview and define job inline
const interview = await createInterview({
  candidateId,
  job: {
    jobTitle: "Senior Backend Engineer",
    jobDescription: "We are looking for a senior engineer...",
    requiredSkills: ["TypeScript", "NestJS", "PostgreSQL"],
    niceToHaveSkills: ["Redis", "AWS"],
    languages: ["EN"],
    experience: "SENIOR",
    contractType: "FULL_TIME",
    location: { workMode: "REMOTE", countryCode: "SK" },
    metadata: { externalJobId: "JOB-12345" },
  },
  agentId: "agent-uuid",
  scheduleTime: new Date(Date.now() + 24 * 60 * 60 * 1000).toISOString(),
});

console.log(`Interview jobId: ${interview.jobId}`);
The inline job is saved as a regular Job entity. You can later fetch and manage it via the Jobs API using the jobId returned in the interview object.

Test Mode

Test mode allows you to create test interviews that immediately complete without consuming billing minutes. This is useful for testing webhook handlers and integration flows.

When to Use Test Mode

  • Testing Webhook Handlers: Verify that your webhook endpoints correctly handle interview.completed and analysis.completed events
  • Integration Testing: Test your application’s interview processing logic without waiting for real interviews
  • Development: Develop and debug features that depend on completed interviews
  • Demo Purposes: Create sample interviews for demonstrations

How Test Mode Works

When you set isTest: true:
  1. Billing Bypass: All billing checks are skipped - no minutes are consumed
  2. Immediate Completion: The interview is created with COMPLETED status immediately
  3. Mock Analysis Data: Realistic screening analysis data is automatically generated and stored
  4. Webhook Events: Both interview.completed and analysis.completed webhook events are triggered
  5. Default Duration: Test interviews have a default duration of 5 minutes

Example: Creating a Test Interview

const testInterview = await createInterview({
  candidate: {
    firstName: "Jane",
    lastName: "Doe",
    email: "[email protected]",
    phoneNumber: "+1234567890",
    gdprExpiryDate: "2026-11-16",
  },
  agentId: "agent-uuid",
  isTest: true, // Enable test mode
});

console.log(`Test interview created: ${testInterview.id}`);
console.log(`Status: ${testInterview.status}`); // "COMPLETED"
console.log(`Duration: ${testInterview.durationMinutes} minutes`); // 5

Test Interview Characteristics

  • Status: Always COMPLETED immediately
  • Duration: 5 minutes (300 seconds)
  • Analysis: Includes mock screening analysis with:
    • Conversation check results (candidateInterest: true, conversationCompleted: true)
    • Candidate analysis scores and recommendations
    • Mock transcript segments
  • Webhooks: Triggers both interview.completed and analysis.completed events
  • Billing: No minutes consumed, no billing checks performed
Test interviews are marked with isTest: true in their metadata. They appear in interview lists and can be queried like normal interviews, but they do not affect billing or production metrics.

Authorizations

Authorization
string
header
required

API key for authentication using Bearer scheme

Body

application/json
candidateId
string<uuid>
required

Existing candidate ID (XOR with candidate). Must exist and belong to the same company as the API key. Existence/company relationship is validated server-side.

Example:

"123e4567-e89b-12d3-a456-426614174000"

jobId
string<uuid>
required

Job ID to associate the interview with (XOR with job). Required when candidate has multiple job assignments and no job is provided. Must belong to the API key's company.

Example:

"123e4567-e89b-12d3-a456-426614174000"

agentId
string<uuid>
required

Existing agent ID (XOR with agent). Must exist and belong to the same company as the API key. Existence/company relationship is validated server-side.

Example:

"987e6543-e21b-12d3-a456-426614174000"

scheduleTime
string<date-time>
required

Scheduled time in ISO 8601 format (max 30 days in future)

Example:

"2025-11-20T10:00:00Z"

job
object

Job for inline creation (XOR with jobId). When provided, a new job will be created and used for the interview. Cannot be combined with jobId.

candidate
object

Candidate for inline creation (XOR with candidateId)

agent
object

Agent for inline creation (XOR with agentId)

metadata
object

Custom metadata for the interview (max 10KB, 5 levels deep, 50 keys)

Example:
{
"externalInterviewId": "INT-789",
"interviewerNotes": "Focus on technical skills"
}
isTest
boolean
default:false

If true, creates a test interview that immediately completes without consuming billing minutes. Triggers webhook events (interview.completed, analysis.completed) for testing webhook handlers.

Example:

false

Response

OK (legacy; prefer 201)

id
string<uuid>
required

Interview ID

Example:

"123e4567-e89b-12d3-a456-426614174000"

candidateId
string<uuid>
required

Candidate ID

Example:

"987e6543-e21b-12d3-a456-426614174000"

agentId
string<uuid>
required

Agent ID

Example:

"456e7890-e12b-34d5-a678-901234567890"

status
enum<string>
required

Interview status

Available options:
UNDEFINED,
SCHEDULED,
CANCELLED,
FAILED,
COMPLETED,
IN_PROGRESS
Example:

"SCHEDULED"

scheduledAt
string<date-time>
required

Scheduled time

Example:

"2025-11-20T10:00:00Z"

createdAt
string
required

Created timestamp

Example:

"2024-11-16T10:30:00Z"

updatedAt
string
required

Updated timestamp

Example:

"2024-11-16T10:30:00Z"

jobId
string<uuid> | null

Job ID associated with this interview, if any

Example:

"123e4567-e89b-12d3-a456-426614174000"

durationMinutes
number

Interview duration in minutes

Example:

15

finishedDate
string<date-time>

Finished date

Example:

"2025-11-20T10:15:00Z"

metadata
object

Custom metadata

Example:
{ "externalInterviewId": "INT-789" }
callAttempts
object[]

Call attempt logs for this interview. Present for phone interviews, typically empty or undefined for online interviews.

analysis
object

Candidate analysis data. Present only if analysis has been generated.

isTest
boolean

Whether this is a test interview. Test interviews are created with isTest=true, immediately complete without consuming billing minutes, and are excluded from billing/usage summaries. Use test interviews for testing webhook handlers and integration flows.

Example:

false