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

# Interview Invite

<Tip>
  Use the same `ats_job_id` across multiple requests to invite candidates to an existing job.
</Tip>

## Candidate Custom Fields

Each candidate object accepts an optional `custom_fields` object containing key-value pairs. These fields are stored on the candidate record.

## Example Request

```json theme={null}
{
  "ats_job_id": "ats-job-12345",
  "job_title": "Senior Software Engineer",
  "job_description": "We are looking for a Senior Software Engineer to join our team and build scalable backend services.",
  "min_experience": 3,
  "max_experience": 5,
  "seniority_level": "Senior",
  "work_type": "Remote",
  "employment_type": "Full Time",
  "location": "New York, NY",
  "skills_required": ["JavaScript", "Node.js", "MongoDB"],
  "skills_good_to_have": ["TypeScript", "Redis", "Docker"],
  "interview_settings": {
    "cutoff_score": 50,
    "interview_duration": "30 Minutes"
  },
  "candidates": [
    {
      "id": "ats-candidate-001",
      "name": "John Doe",
      "email": "john.doe@example.com",
      "phone": "+1234567890",
      "custom_fields": {
        "years_of_experience": "5",
        "current_company": "Acme Corp"
      }
    }
  ]
}
```

## Example Response

```json theme={null}
{
  "success": true,
  "data": {
    "project_id": "64a1b2c3d4e5f6a7b8c9d0e1",
    "job_url": "https://jobs.tidyhire.app/company/acme/job/64a1b2c3d4e5f6a7b8c9d0e2",
    "project_url": "https://platform.tidyhire.app/app/projects/64a1b2c3d4e5f6a7b8c9d0e1",
    "interviews": [
      {
        "id": "64a1b2c3d4e5f6a7b8c9d0e3",
        "candidate_id": "ats-candidate-001",
        "name": "John Doe",
        "email": "john.doe@example.com",
        "phone": "+1234567890",
        "status": "success",
        "message": "Interview invitation is being processed"
      }
    ]
  }
}
```


## OpenAPI

````yaml POST /api/public/v1/interview/invite
openapi: 3.1.0
info:
  title: Tidyhire API
  description: Tidyhire Public API for ATS integrations
  version: 1.0.0
servers:
  - url: https://api.tidyhire.app
    description: Production
security:
  - apiKey: []
paths:
  /api/public/v1/interview/invite:
    post:
      tags:
        - Interview
      summary: Interview Invite
      operationId: interviewInvite
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/InviteRequest'
      responses:
        '200':
          description: Success.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InviteSuccessResponse'
        '400':
          description: Validation Error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ValidationErrorResponse'
        '500':
          description: Internal Error.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/InternalErrorResponse'
      security:
        - apiKey: []
components:
  schemas:
    InviteRequest:
      type: object
      required:
        - ats_job_id
        - job_title
        - job_description
        - min_experience
        - max_experience
        - seniority_level
        - work_type
        - employment_type
        - location
        - skills_required
        - skills_good_to_have
        - candidates
      properties:
        ats_job_id:
          type: string
          minLength: 1
          maxLength: 200
          description: >-
            A unique job identifier from your ATS to link this job. If a project
            with this ats_job_id already exists, candidates are added to it.
            Otherwise a new project and job are created.
          example: ats-job-12345
        job_title:
          type: string
          minLength: 1
          description: >-
            The title of the job position. Hyperlinks are not allowed in this
            field.
          example: Senior Software Engineer
        job_description:
          type: string
          minLength: 1
          description: >-
            A detailed description of the job role and responsibilities.
            Hyperlinks are not allowed in this field.
          example: >-
            We are looking for a Senior Software Engineer to join our team and
            build scalable backend services.
        min_experience:
          type: number
          description: Minimum years of experience required.
          example: 3
        max_experience:
          type: number
          description: Maximum years of experience required.
          example: 5
        seniority_level:
          type: string
          enum:
            - Entry
            - Mid
            - Senior
            - Lead
            - Principal
            - Staff
          description: Seniority level for the role.
          example: Senior
        work_type:
          type: string
          enum:
            - Remote
            - On Site
            - Hybrid
          description: Work arrangement type.
          example: Remote
        employment_type:
          type: string
          enum:
            - Full Time
            - Part Time
            - Contract
            - Freelance
          description: Type of employment.
          example: Full Time
        location:
          type: string
          minLength: 1
          description: Job location.
          example: New York, NY
        skills_required:
          type: array
          items:
            type: string
          minItems: 3
          description: List of required skills. Minimum 3 skills.
          example:
            - JavaScript
            - Node.js
            - MongoDB
        skills_good_to_have:
          type: array
          items:
            type: string
          minItems: 3
          description: List of preferred skills. Minimum 3 skills.
          example:
            - TypeScript
            - Redis
            - Docker
        interview_questions:
          type: array
          items:
            $ref: '#/components/schemas/Question'
          description: >-
            Pre-generated interview questions. If provided, AI question
            generation is skipped.
        interview_settings:
          $ref: '#/components/schemas/InterviewSettings'
        candidates:
          type: array
          items:
            $ref: '#/components/schemas/Candidate'
          minItems: 1
          description: List of candidates to invite. Minimum 1 candidate.
    InviteSuccessResponse:
      type: object
      example:
        success: true
        data:
          project_id: 64a1b2c3d4e5f6a7b8c9d0e1
          job_url: https://jobs.tidyhire.app/company/acme/job/64a1b2c3d4e5f6a7b8c9d0e2
          project_url: https://platform.tidyhire.app/app/projects/64a1b2c3d4e5f6a7b8c9d0e1
          interviews:
            - id: 64a1b2c3d4e5f6a7b8c9d0e3
              candidate_id: ats-candidate-001
              name: John Doe
              email: john.doe@example.com
              phone: '+1234567890'
              status: success
              message: Interview invitation is being processed
      properties:
        success:
          type: boolean
          example: true
        data:
          type: object
          properties:
            project_id:
              type: string
              description: The project ID (new or existing).
            job_url:
              type: string
              description: Public URL for the job listing.
            project_url:
              type: string
              description: Dashboard URL for the project.
            interviews:
              type: array
              description: All interview entries.
              items:
                $ref: '#/components/schemas/InterviewEntry'
    ValidationErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        code:
          type: string
          example: VALIDATION_ERROR
        message:
          type: string
          example: Request validation failed
        errors:
          type: array
          items:
            type: object
            properties:
              field:
                type: string
                example: candidates.0.name
              message:
                type: string
                example: Candidate name must be at least 3 characters
    InternalErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        code:
          type: string
          example: UNKNOWN_ERROR
        message:
          type: string
          example: Something went wrong.
    Question:
      oneOf:
        - $ref: '#/components/schemas/VerbalQuestion'
        - $ref: '#/components/schemas/TaskQuestion'
      discriminator:
        propertyName: type
        mapping:
          verbal:
            $ref: '#/components/schemas/VerbalQuestion'
          task:
            $ref: '#/components/schemas/TaskQuestion'
    InterviewSettings:
      type: object
      properties:
        cutoff_score:
          type: number
          minimum: 0
          maximum: 100
          default: 50
          description: Minimum passing score (0-100).
          example: 50
        interview_duration:
          type: string
          enum:
            - 15 Minutes
            - 30 Minutes
            - 1 hour
            - 2 hours
          default: 30 Minutes
          description: Duration of the interview.
          example: 30 Minutes
    Candidate:
      type: object
      required:
        - id
        - name
        - email
      properties:
        id:
          type: string
          minLength: 1
          description: >-
            A unique candidate identifier from your system (e.g. ATS candidate
            ID). Used to deduplicate candidates within a project — if a
            candidate with this ID already exists, the existing entry is
            returned and no duplicate invitation is sent.
          example: ats-candidate-001
        name:
          type: string
          minLength: 3
          pattern: ^[a-zA-Z][a-zA-Z. ]*$
          description: >-
            Full name of the candidate. Only letters, dots, and spaces allowed.
            Minimum 3 characters. Auto-converted to Title Case.
          example: John Doe
        email:
          type: string
          format: email
          description: Email address of the candidate. Auto-converted to lowercase.
          example: john.doe@example.com
        phone:
          type: string
          description: >-
            Phone number of the candidate. Non-digit characters (except leading
            +) are stripped automatically.
          example: '+1234567890'
    InterviewEntry:
      type: object
      properties:
        id:
          type: string
          nullable: true
          description: Queue entry ID, or null if skipped.
          example: 64a1b2c3d4e5f6a7b8c9d0e3
        candidate_id:
          type: string
          description: The candidate ID from your system.
          example: ats-candidate-001
        name:
          type: string
          description: Candidate name (title-cased).
          example: John Doe
        email:
          type: string
          description: Candidate email (lowercased).
          example: john.doe@example.com
        phone:
          type: string
          nullable: true
          description: Candidate phone number, or null if not provided.
          example: '+1234567890'
        status:
          type: string
          enum:
            - success
            - failed
          description: Candidate-level status.
          example: success
        message:
          type: string
          description: Human-readable status message.
          example: Interview invitation is being processed
    VerbalQuestion:
      type: object
      required:
        - id
        - question
        - type
      properties:
        id:
          type: string
          minLength: 1
          description: Unique question identifier.
          example: a1b2c3d4e5f60123456789abcdef0123
        question:
          type: string
          minLength: 1
          description: The interview question text.
          example: >-
            Tell me about a production application you led. What architecture
            choices did you make?
        type:
          type: string
          enum:
            - verbal
          description: Question type.
          example: verbal
    TaskQuestion:
      type: object
      required:
        - id
        - question
        - task
        - type
      properties:
        id:
          type: string
          minLength: 1
          description: Unique question identifier.
          example: 07f8e9d1c2b3456789abcdef0123456789ab
        question:
          type: string
          minLength: 1
          description: The interview question text.
          example: >-
            Implement an Angular component and service to display a paginated,
            sortable analytics table.
        task:
          $ref: '#/components/schemas/QuestionTask'
        type:
          type: string
          enum:
            - task
          description: Question type.
          example: task
    QuestionTask:
      type: object
      required:
        - problem_statement
        - type
      properties:
        language:
          type: string
          description: >-
            Programming language for the task. Required for `code` tasks;
            optional for `general` tasks (use "N/A" if not applicable).
          example: TypeScript
        problem_statement:
          type: string
          minLength: 1
          description: Detailed problem statement for the candidate to solve.
          example: >-
            Create an Angular service that calls a REST endpoint
            /api/patients/search...
        starter_code:
          type: string
          description: >-
            Starter code template provided to the candidate. Required for `code`
            tasks; optional for `general` tasks.
          example: |-
            import { Injectable } from '@angular/core';
            ...
        type:
          type: string
          enum:
            - code
            - general
          description: Task type — `code` for coding tasks, `general` for non-coding tasks.
          example: code
  securitySchemes:
    apiKey:
      type: apiKey
      in: header
      name: x-tidyhire-api-key
      description: Your Tidyhire API key

````