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

# Candidates

> API endpoints for managing and retrieving candidate data

The Candidates API allows you to add candidates, bulk upload resumes, retrieve parsed candidate information, list candidates with filters, and fetch individual candidate details.

## Add Candidate

Create a new candidate in your company. If a candidate with the same email already exists, the existing candidate will be returned along with a flag indicating it's an existing candidate.

### `POST /candidates`

### Authentication

Requires API key authentication via `Authorization: Bearer YOUR_API_KEY` header.

### Request Body

| Field                | Type            | Required | Description                                                                                                                                                             |
| -------------------- | --------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `firstName`          | string          | Yes      | Candidate's first name (min 1, max 200 characters)                                                                                                                      |
| `lastName`           | string          | Yes      | Candidate's last name (min 1, max 200 characters)                                                                                                                       |
| `email`              | string          | Yes      | Candidate's email address (must be valid email format, max 500 characters)                                                                                              |
| `phone`              | string          | No       | Candidate's phone number                                                                                                                                                |
| `resume`             | string          | No       | URL to candidate's resume file (must start with http\:// or https\://). If provided and `shouldParseResume` is true, the resume will be downloaded, stored, and parsed. |
| `currentJobTitle`    | string          | No       | Candidate's current job title                                                                                                                                           |
| `currentCompany`     | string          | No       | Candidate's current company name                                                                                                                                        |
| `city`               | string          | No       | City location                                                                                                                                                           |
| `country`            | string          | No       | Country                                                                                                                                                                 |
| `skills`             | array or string | No       | Array of skills (max 200 characters each) or comma-separated string. Arrays will be converted to comma-separated strings.                                               |
| `linkedin`           | string          | No       | LinkedIn profile URL                                                                                                                                                    |
| `coverLetter`        | string          | No       | Cover letter text                                                                                                                                                       |
| `gender`             | string          | No       | Gender. Must be one of: "male", "female", "other", "Male", "Female", "Other"                                                                                            |
| `dateOfBirth`        | string          | No       | Date of birth (ISO 8601 format)                                                                                                                                         |
| `nationality`        | string          | No       | Nationality                                                                                                                                                             |
| `industry`           | string          | No       | Industry                                                                                                                                                                |
| `category`           | string          | No       | Category                                                                                                                                                                |
| `jobId`              | integer         | No       | Job ID to associate the candidate with. If provided, resume scoring will be automatically enabled.                                                                      |
| `shouldParseResume`  | boolean         | No       | Whether to parse the resume. Default: `true`. Set to `false` if you're providing parsed data directly (educations, workExperiences, etc.).                              |
| `majors`             | string          | No       | Majors/fields of study (comma-separated string or single value)                                                                                                         |
| `summary`            | string          | No       | Professional summary (max 5000 characters)                                                                                                                              |
| `languages`          | array           | No       | Array of language strings (max 100 characters each)                                                                                                                     |
| `educations`         | array           | No       | Array of education objects (see Education Object below)                                                                                                                 |
| `githubUrl`          | string          | No       | GitHub profile URL (must be valid URL)                                                                                                                                  |
| `certifications`     | array           | No       | Array of certification objects (see Certification Object below)                                                                                                         |
| `workExperiences`    | array           | No       | Array of work experience objects (see Work Experience Object below)                                                                                                     |
| `projectExperiences` | array           | No       | Array of project experience objects (see Project Experience Object below)                                                                                               |

### Request Body Example

```json theme={null}
{
  "firstName": "John",
  "lastName": "Doe",
  "email": "john.doe@example.com",
  "phone": "+1234567890",
  "resume": "https://example.com/resumes/john-doe.pdf",
  "currentJobTitle": "Software Engineer",
  "currentCompany": "Tech Corp",
  "city": "San Francisco",
  "country": "United States",
  "skills": ["JavaScript", "React", "Node.js"],
  "linkedin": "https://linkedin.com/in/johndoe",
  "coverLetter": "I am interested in joining your team...",
  "gender": "Male",
  "dateOfBirth": "1995-05-15",
  "nationality": "American",
  "industry": "Technology",
  "category": "Engineering",
  "jobId": 12345,
  "shouldParseResume": true,
  "majors": "Computer Science",
  "summary": "Experienced software engineer with 5+ years...",
  "languages": ["English", "Spanish"],
  "educations": [
    {
      "degree": "Bachelor's",
      "university": "University of California",
      "graduation_year": "2019"
    }
  ],
  "workExperiences": [
    {
      "title": "Senior Software Engineer",
      "company": "Tech Corp",
      "start_date": "2020-01-01",
      "responsibilities": [
        "Led development of...",
        "Managed team of 5 engineers"
      ]
    }
  ],
  "projectExperiences": [
    {
      "title": "E-commerce Platform",
      "technology_used": "React, Node.js, PostgreSQL",
      "summary": [
        "Built a full-stack e-commerce platform...",
        "Implemented payment gateway integration"
      ]
    }
  ],
  "certifications": [
    {
      "name": "AWS Certified Solutions Architect",
      "provider": "Amazon Web Services"
    }
  ],
  "githubUrl": "https://github.com/johndoe"
}
```

### Example Request

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/candidates" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@example.com",
    "phone": "+1234567890",
    "currentJobTitle": "Software Engineer",
    "currentCompany": "Tech Corp",
    "city": "San Francisco",
    "country": "United States",
    "skills": ["JavaScript", "React", "Node.js"],
    "resume": "https://example.com/resumes/john-doe.pdf",
    "jobId": 12345,
    "shouldParseResume": true
  }'
```

### Example Response

```json theme={null}
{
  "status": "success",
  "data": {
    "candidate": {
      "id": 12345,
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@example.com",
      "phone": "+1234567890",
      "currentJobTitle": "Software Engineer",
      "currentCompany": "Tech Corp",
      "city": "San Francisco",
      "country": "United States",
      "skills": ["JavaScript", "React", "Node.js"],
      "resume": "https://storage.example.com/resumes/john-doe.pdf",
      "coverLetter": "I am interested in joining your team...",
      "majors": ["Computer Science"],
      "summary": "Experienced software engineer with 5+ years...",
      "languages": ["English", "Spanish"],
      "educations": [
        {
          "degree": "Bachelor's",
          "field": "Computer Science",
          "institution": "University of California",
          "startDate": "2015-09-01",
          "endDate": "2019-06-01"
        }
      ],
      "workExperiences": [
        {
          "title": "Senior Software Engineer",
          "company": "Tech Corp",
          "location": "San Francisco, CA",
          "startDate": "2020-01-01",
          "endDate": null,
          "description": "Led development of..."
        }
      ],
      "projectExperiences": [
        {
          "name": "E-commerce Platform",
          "description": "Built a full-stack e-commerce platform...",
          "technologies": ["React", "Node.js", "PostgreSQL"]
        }
      ],
      "certifications": [
        {
          "name": "AWS Certified Solutions Architect",
          "issuer": "Amazon Web Services",
          "issueDate": "2022-03-15",
          "expiryDate": "2025-03-15"
        }
      ],
      "githubUrl": "https://github.com/johndoe",
      "linkedin": "https://linkedin.com/in/johndoe",
      "gender": "Male",
      "dateOfBirth": "1995-05-15",
      "nationality": "American",
      "industry": "Technology",
      "category": "Engineering"
    },
    "jobCandidateId": 67890,
    "isExisting": false,
    "isAlreadyInJob": false
  }
}
```

### Response Fields

| Field                 | Type    | Description                                                                                                      |
| --------------------- | ------- | ---------------------------------------------------------------------------------------------------------------- |
| `status`              | string  | Response status ("success")                                                                                      |
| `data.candidate`      | object  | The created or existing candidate object with all fields flattened                                               |
| `data.jobCandidateId` | integer | The job candidate ID if `jobId` was provided and candidate was added to the job, otherwise `null`                |
| `data.isExisting`     | boolean | Indicates if the candidate already existed (true) or was newly created (false)                                   |
| `data.isAlreadyInJob` | boolean | Indicates if the candidate was already associated with the specified job (only present when `jobId` is provided) |

### Candidate Object Fields

The candidate object includes all standard candidate fields with flattened structure (miscellaneous fields are extracted to the top level):

* Basic info: `id`, `firstName`, `lastName`, `email`, `phone`
* Professional info: `currentJobTitle`, `currentCompany`, `city`, `country`, `skills`
* Resume: `resume` (URL)
* Extended info: `majors`, `summary`, `languages`, `educations`, `workExperiences`, `projectExperiences`, `certifications`
* Social: `githubUrl`, `linkedin`
* Additional: `coverLetter`, `gender`, `dateOfBirth`, `nationality`, `industry`, `category`

### Notes

* **Duplicate Email Handling**: If a candidate with the same email already exists, the existing candidate will be returned with `isExisting: true`
* **Job Association**: If `jobId` is provided:
  * The candidate will be associated with that job and `jobCandidateId` will be returned
  * Resume scoring will be automatically enabled
  * If the candidate is already in the job, in response, `isAlreadyInJob` will be `true`
* **Resume Parsing**:
  * By default (`shouldParseResume: true`), if a `resume` URL is provided, it will be downloaded, stored, and parsed asynchronously
  * Webhook events will be sent when parsing completes or fails
* **Resume Scoring**:
  * Automatically enabled when `jobId` is provided
  * If `shouldParseResume` is `false` and `jobId` is provided, you must include `city`, `country`, `educations`, and `workExperiences` for scoring to work.
* **Skills Format**: Skills can be provided as an array or comma-separated string.
* **Response Structure**: All miscellaneous fields (educations, workExperiences, etc.) are flattened to the top level in the response
* **Validation**: All fields are validated using schema. Invalid requests will return detailed error messages with field-specific errors

### Webhook Events

When you add a candidate with a resume URL, webhook events are triggered for resume parsing:

* **`resume.single_parse.completed`**: Sent when the resume parsing completes successfully
  ```json theme={null}
  {
    "event": "resume.single_parse.completed",
    "timestamp": "2024-01-20T14:45:00Z",
    "companyId": "companyId_1",
    "data": {
      "candidateId": 12345,
      "status": "SUCCESS"
    }
  }
  ```

* **`resume.single_parse.failed`**: Sent when the resume parsing fails
  ```json theme={null}
  {
    "event": "resume.single_parse.failed",
    "timestamp": "2024-01-20T14:45:00Z",
    "companyId": "companyId_1",
    "data": {
      "candidateId": 12345,
      "status": "FAILED",
      "error": "Resume parsing failed"
    }
  }
  ```

When you add a candidate without resume but with a `jobId`, webhook events are triggered for scoring:

* **`job.candidate.score.completed`**: Sent when AI scoring is completed for a candidate's application to a job
  ```json theme={null}
  {
    "event": "job.candidate.score.completed",
    "timestamp": "2024-01-20T14:45:00Z",
    "companyId": 12345,
    "data": {
      "jobId": 12345,
      "jobCandidateId": 101,
      "candidateId": "candidateId_1"
    }
  }
  ```

* **`job.candidate.score.failed`**: Sent when AI scoring fails for a candidate's application to a job
  ```json theme={null}
  {
    "event": "job.candidate.score.failed",
    "timestamp": "2024-01-20T14:45:00Z",
    "companyId": 12345,
    "data": {
      "jobId": 12345,
      "jobCandidateId": 101,
      "candidateId": "candidateId_1",
      "error": "Scoring failed: insufficient candidate data"
    }
  }
  ```

### Error Responses

**Missing firstName**:

```json theme={null}
{
  "error": {
    "code": "MISSING_FIRST_NAME",
    "type": "validation_error",
    "message": "firstName is required"
  }
}
```

**Missing lastName**:

```json theme={null}
{
  "error": {
    "code": "MISSING_LAST_NAME",
    "type": "validation_error",
    "message": "lastName is required"
  }
}
```

**Missing email**:

```json theme={null}
{
  "error": {
    "code": "MISSING_EMAIL",
    "type": "validation_error",
    "message": "email is required"
  }
}
```

**Invalid request (validation errors)**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "One or more fields are invalid.",
    "details": {
      "email": "email must be a valid email address",
      "resume": "resume must be a valid URL starting with http:// or https://",
      "firstName": "firstName is required"
    }
  }
}
```

**Insufficient credits for resume parsing**:

```json theme={null}
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "type": "payment_error",
    "message": "Insufficient credits for resume parsing"
  }
}
```

**Insufficient credits for resume scoring**:

```json theme={null}
{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "type": "payment_error",
    "message": "Insufficient credits for resume scoring"
  }
}
```

**Missing scoring fields** (when scoring without parsing):

```json theme={null}
{
  "error": {
    "code": "MISSING_SCORING_FIELDS",
    "type": "validation_error",
    "message": "When scoring is required (jobId provided) without parsing, these fields are required: educations, workExperiences, city, country",
    "details": {
      "missingFields": ["city", "country"]
    }
  }
}
```

### Object Schemas

#### Education Object

| Field             | Type   | Required | Description                                      |
| ----------------- | ------ | -------- | ------------------------------------------------ |
| `degree`          | string | No       | Degree name (max 500 characters)                 |
| `university`      | string | No       | University/institution name (max 500 characters) |
| `graduation_year` | string | No       | Graduation year (max 50 characters)              |

#### Work Experience Object

| Field              | Type   | Required | Description                                                         |
| ------------------ | ------ | -------- | ------------------------------------------------------------------- |
| `title`            | string | No       | Job title (max 500 characters)                                      |
| `company`          | string | No       | Company name (max 500 characters)                                   |
| `start_date`       | string | No       | Start date (max 50 characters)                                      |
| `end_date`         | string | No       | End date (max 50 characters). Omit this field for current positions |
| `responsibilities` | array  | No       | Array of responsibility strings (max 2000 characters each)          |

#### Project Experience Object

| Field             | Type   | Required | Description                                         |
| ----------------- | ------ | -------- | --------------------------------------------------- |
| `title`           | string | No       | Project title (max 500 characters)                  |
| `technology_used` | string | No       | Technologies used (max 1000 characters)             |
| `summary`         | array  | No       | Array of summary strings (max 2000 characters each) |

#### Certification Object

| Field      | Type   | Required | Description                                        |
| ---------- | ------ | -------- | -------------------------------------------------- |
| `name`     | string | Yes      | Certification name (max 500 characters)            |
| `provider` | string | Yes      | Certification provider/issuer (max 500 characters) |

## List Candidates

Retrieve a paginated list of candidates in your company with advanced filtering options.

### `GET /candidates/list`

### Authentication

Requires API key authentication via `Authorization: Bearer YOUR_API_KEY` header.

### Query Parameters

| Parameter                        | Type    | Required | Description                                                          |
| -------------------------------- | ------- | -------- | -------------------------------------------------------------------- |
| `jobIds`                         | string  | No       | Comma-separated list of job IDs (integers) to filter candidates by   |
| `stageIds`                       | string  | No       | Comma-separated list of stage IDs to filter candidates by            |
| `searchTerm`                     | string  | No       | Search term to filter candidates by name, email, or other fields     |
| `currentJobTitle`                | string  | No       | Filter by candidate's current job title                              |
| `currentCompany`                 | string  | No       | Filter by candidate's current company                                |
| `candidatePhone`                 | string  | No       | Filter by candidate's phone number                                   |
| `candidateEmail`                 | string  | No       | Filter by candidate's email address                                  |
| `skills`                         | string  | No       | Comma-separated list of skills to filter by (case-insensitive)       |
| `groupIds`                       | string  | No       | Comma-separated list of group IDs to filter by                       |
| `includeOnlyRejecetedCandidates` | string  | No       | Set to "true" to include only rejected candidates (default: "false") |
| `source`                         | string  | No       | Filter by candidate source                                           |
| `perPage`                        | integer | No       | Items per page. Must be one of: 10, 20, 40, 80, 100 (default: 10)    |
| `pageNumber`                     | integer | No       | Page number (0-indexed, default: 0)                                  |

### Example Request

```bash theme={null}
curl -X GET "https://partner-api.taptalent.io/v1/partner/candidates/list?pageNumber=0&perPage=20&skills=javascript,react&currentJobTitle=Software%20Engineer" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json"
```

### Example Response

```json theme={null}
{
  "status": "success",
  "data": {
    "candidates": [
      {
        "id": 12345,
        "firstName": "John",
        "lastName": "Doe",
        "email": "john.doe@example.com",
        "phone": "+1234567890",
        "currentJobTitle": "Software Engineer",
        "currentCompany": "Tech Corp",
        "city": "San Francisco",
        "country": "United States",
        "skills": ["JavaScript", "React", "Node.js"],
        "resume": "https://storage.example.com/resumes/john-doe.pdf",
        "majors": ["Computer Science"],
        "summary": "Experienced software engineer...",
        "languages": ["English"],
        "educations": [
          {
            "degree": "Bachelor's",
            "field": "Computer Science",
            "institution": "University"
          }
        ],
        "workExperiences": [
          {
            "title": "Software Engineer",
            "company": "Tech Corp",
            "duration": "2 years"
          }
        ],
        "projectExperiences": [],
        "certifications": [],
        "githubUrl": "https://github.com/johndoe",
        "linkedin": "https://linkedin.com/in/johndoe"
      }
    ],
    "pagination": {
      "page": 0,
      "perPage": 20,
      "totalCandidates": 150,
      "totalPages": 8,
      "hasNextPage": true
    }
  }
}
```

### Response Fields

| Field                             | Type    | Description                                     |
| --------------------------------- | ------- | ----------------------------------------------- |
| `status`                          | string  | Response status ("success")                     |
| `data.candidates`                 | array   | Array of candidate objects                      |
| `data.pagination.page`            | number  | Current page number (0-indexed)                 |
| `data.pagination.perPage`         | number  | Number of items per page                        |
| `data.pagination.totalCandidates` | number  | Total number of candidates matching the filters |
| `data.pagination.totalPages`      | number  | Total number of pages                           |
| `data.pagination.hasNextPage`     | boolean | Indicates if there are more pages               |

### Candidate Object Fields

The candidate objects include all standard candidate fields:

* Basic info: `id`, `firstName`, `lastName`, `email`, `phone`
* Professional info: `currentJobTitle`, `currentCompany`, `city`, `country`, `skills`
* Resume: `resume` (URL)
* Extended info: `majors`, `summary`, `languages`, `educations`, `workExperiences`, `projectExperiences`, `certifications`
* Social: `githubUrl`, `linkedin`

### Error Responses

**Invalid perPage value**:

```json theme={null}
{
  "error": {
    "code": "INVALID_PER_PAGE",
    "type": "validation_error",
    "message": "perPage must be one of: 10, 20, 40, 80, 100"
  }
}
```

## Get Candidate Details

Retrieve detailed information about a specific candidate, including their associated jobs.

### `GET /candidates/:candidateId`

### Authentication

Requires API key authentication via `Authorization: Bearer YOUR_API_KEY` header.

### Path Parameters

| Parameter     | Type    | Description                            |
| ------------- | ------- | -------------------------------------- |
| `candidateId` | integer | The unique identifier of the candidate |

### Example Request

```bash theme={null}
curl -X GET "https://partner-api.taptalent.io/v1/partner/candidates/12345" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json"
```

### Example Response

```json theme={null}
{
  "status": "success",
  "data": {
    "id": 12345,
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@example.com",
    "phone": "+1234567890",
    "currentJobTitle": "Software Engineer",
    "currentCompany": "Tech Corp",
    "city": "San Francisco",
    "state": "California",
    "country": "United States",
    "skills": ["JavaScript", "React", "Node.js"],
    "resume": "https://storage.example.com/resumes/john-doe.pdf",
    "coverLetter": "I am interested in...",
    "majors": ["Computer Science"],
    "summary": "Experienced software engineer with 5+ years...",
    "languages": ["English", "Spanish"],
    "educations": [
      {
        "degree": "Bachelor's",
        "field": "Computer Science",
        "institution": "University of California",
        "startDate": "2015-09-01",
        "endDate": "2019-06-01"
      }
    ],
    "workExperiences": [
      {
        "title": "Senior Software Engineer",
        "company": "Tech Corp",
        "location": "San Francisco, CA",
        "startDate": "2020-01-01",
        "endDate": null,
        "description": "Led development of..."
      }
    ],
    "projectExperiences": [
      {
        "name": "E-commerce Platform",
        "description": "Built a full-stack e-commerce platform...",
        "technologies": ["React", "Node.js", "PostgreSQL"]
      }
    ],
    "certifications": [
      {
        "name": "AWS Certified Solutions Architect",
        "issuer": "Amazon Web Services",
        "issueDate": "2022-03-15",
        "expiryDate": "2025-03-15"
      }
    ],
    "githubUrl": "https://github.com/johndoe",
    "linkedin": "https://linkedin.com/in/johndoe",
    "gender": "Male",
    "dateOfBirth": "1995-05-15",
    "nationality": "American",
    "industry": "Technology",
    "category": "Engineering"
  }
}
```

### Response Fields

The response includes all candidate fields with flattened structure (miscellaneous fields are extracted to the top level):

| Field                | Type    | Description                         |
| -------------------- | ------- | ----------------------------------- |
| `id`                 | integer | Unique candidate identifier         |
| `firstName`          | string  | Candidate's first name              |
| `lastName`           | string  | Candidate's last name               |
| `email`              | string  | Candidate's email address           |
| `phone`              | string  | Candidate's phone number            |
| `currentJobTitle`    | string  | Current job title                   |
| `currentCompany`     | string  | Current company name                |
| `city`               | string  | City location                       |
| `state`              | string  | State/province                      |
| `country`            | string  | Country                             |
| `skills`             | array   | Array of skills                     |
| `resume`             | string  | URL to resume file                  |
| `coverLetter`        | string  | Cover letter text                   |
| `majors`             | array   | Array of majors/fields of study     |
| `summary`            | string  | Professional summary                |
| `languages`          | array   | Array of languages                  |
| `educations`         | array   | Array of education objects          |
| `workExperiences`    | array   | Array of work experience objects    |
| `projectExperiences` | array   | Array of project experience objects |
| `certifications`     | array   | Array of certification objects      |
| `githubUrl`          | string  | GitHub profile URL                  |
| `linkedin`           | string  | LinkedIn profile URL                |
| `gender`             | string  | Gender                              |
| `dateOfBirth`        | string  | Date of birth                       |
| `nationality`        | string  | Nationality                         |
| `industry`           | string  | Industry                            |
| `category`           | string  | Category                            |

### Error Responses

**Missing candidateId**:

```json theme={null}
{
  "error": {
    "code": "MISSING_CANDIDATE_ID",
    "type": "validation_error",
    "message": "candidateId is required"
  }
}
```

**Candidate not found**:

```json theme={null}
{
  "error": {
    "code": "CANDIDATE_NOT_FOUND",
    "type": "resource_error",
    "message": "Candidate not found"
  }
}
```

## Update Candidate

Update a candidate's profile. This is a partial update: send only the fields you want to change. All request body fields are optional, but at least one must be provided.

### `PATCH /candidates/:candidateId`

### Authentication

Requires API key authentication via `Authorization: Bearer YOUR_API_KEY` header.

### Path Parameters

| Parameter     | Type    | Required | Description                            |
| ------------- | ------- | -------- | -------------------------------------- |
| `candidateId` | integer | Yes      | The unique identifier of the candidate |

### Request Body (all optional; at least one required)

Same fields as [Add Candidate](/api-reference/candidates#add-candidate) are supported, except `jobId` and `shouldParseResume`. Include only the fields you want to update.

| Field                | Type            | Description                                                       |
| -------------------- | --------------- | ----------------------------------------------------------------- |
| `firstName`          | string          | First name (min 1, max 200 characters)                            |
| `lastName`           | string          | Last name (min 1, max 200 characters)                             |
| `email`              | string          | Email address (valid format). Must be unique within your company. |
| `phone`              | string          | Phone number                                                      |
| `currentJobTitle`    | string          | Current job title                                                 |
| `currentCompany`     | string          | Current company                                                   |
| `city`               | string          | City                                                              |
| `country`            | string          | Country                                                           |
| `skills`             | array or string | Skills (array or comma-separated)                                 |
| `linkedin`           | string          | LinkedIn profile URL                                              |
| `coverLetter`        | string          | Cover letter text                                                 |
| `gender`             | string          | One of: "male", "female", "other", "Male", "Female", "Other"      |
| `dateOfBirth`        | string          | Date of birth (ISO 8601)                                          |
| `nationality`        | string          | Nationality                                                       |
| `industry`           | string          | Industry                                                          |
| `category`           | string          | Category                                                          |
| `majors`             | string          | Majors/fields of study                                            |
| `summary`            | string          | Professional summary (max 5000 characters)                        |
| `languages`          | array           | Array of language strings                                         |
| `educations`         | array           | Array of education objects (see Add Candidate schema)             |
| `githubUrl`          | string          | GitHub profile URL                                                |
| `certifications`     | array           | Array of certification objects                                    |
| `workExperiences`    | array           | Array of work experience objects                                  |
| `projectExperiences` | array           | Array of project experience objects                               |

### Example Request

```bash theme={null}
curl -X PATCH "https://partner-api.taptalent.io/v1/partner/candidates/12345" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "currentJobTitle": "Senior Software Engineer",
    "currentCompany": "New Tech Corp",
    "phone": "+1234567890"
  }'
```

### Example Response

```json theme={null}
{
  "status": "success",
  "message": "Candidate updated successfully",
  "data": {
    "id": 12345,
    "firstName": "John",
    "lastName": "Doe",
    "email": "john.doe@example.com",
    "phone": "+1234567890",
    "currentJobTitle": "Senior Software Engineer",
    "currentCompany": "New Tech Corp",
    "city": "San Francisco",
    "country": "United States",
    "skills": ["JavaScript", "React", "Node.js"],
    "resume": "https://storage.example.com/resumes/john-doe.pdf",
    "majors": ["Computer Science"],
    "summary": "Experienced software engineer...",
    "languages": ["English", "Spanish"],
    "educations": [],
    "workExperiences": [],
    "projectExperiences": [],
    "certifications": [],
    "githubUrl": "https://github.com/johndoe",
    "linkedin": "https://linkedin.com/in/johndoe"
  }
}
```

### Notes

* **Partial update**: Only included fields are updated; others are left unchanged.
* **Email uniqueness**: If you change `email`, it must not already exist for another candidate in your company.
* **Resume**: Updating resume URL is not supported via this endpoint.

### Error Responses

**Invalid candidateId**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Invalid candidateId"
  }
}
```

**Candidate not found**:

```json theme={null}
{
  "error": {
    "code": "CANDIDATE_NOT_FOUND",
    "type": "resource_error",
    "message": "Candidate not found"
  }
}
```

**Duplicate email**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Another candidate with this email already exists in your company"
  }
}
```

**Validation errors**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "One or more fields are invalid.",
    "details": {
      "email": "email must be a valid email address"
    }
  }
}
```

## Bulk Upload Resumes

Upload multiple resumes for parsing and candidate creation.

### `POST /candidates/bulk/resume`

### Authentication

Requires API key authentication via `Authorization: Bearer YOUR_API_KEY` header.

### Request Body

| Field        | Type             | Required | Description                                                                                                     |
| ------------ | ---------------- | -------- | --------------------------------------------------------------------------------------------------------------- |
| `resumeURLs` | array of strings | Yes      | Array of publicly accessible URLs pointing to resume files (PDF, DOC, DOCX). Maximum 5,000 resumes per request. |

### Request Body Example

```json theme={null}
{
  "resumeURLs": [
    "https://example.com/resumes/john-doe.pdf",
    "https://example.com/resumes/jane-smith.docx",
    "https://example.com/resumes/bob-johnson.pdf"
  ]
}
```

### Example Request

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/candidates/bulk/resume" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "resumeURLs": [
      "https://example.com/resumes/john-doe.pdf",
      "https://example.com/resumes/jane-smith.docx"
    ]
  }'
```

### Example Response

```json theme={null}
{
  "success": true,
  "data": {
    "batchId": 12345,
    "fileCount": 2
  }
}
```

### Response Fields

| Field            | Type    | Description                                                              |
| ---------------- | ------- | ------------------------------------------------------------------------ |
| `success`        | boolean | Indicates if the request was successful                                  |
| `data.batchId`   | integer | Unique identifier for this batch. Use this to retrieve candidates later. |
| `data.fileCount` | number  | Number of resumes in the batch                                           |

### Validation Rules

* `resumeURLs` must be provided and cannot be empty
* `resumeURLs` must be an array
* Each URL must be a non-empty string (whitespace-only strings are invalid)
* URLs must be publicly accessible
* Maximum 5,000 resume URLs per request

### Webhook Events

When you upload resumes, webhook events are triggered:

* **`resume.bulk_upload_parse.started`**: Sent when batch processing starts
  ```json theme={null}
  {
    "event": "resume.bulk_upload_parse.started",
    "timestamp": "2024-01-20T14:45:00Z",
    "companyId": "companyId_1",
    "data": {
      "batchId": 12345,
      "fileCount": 2,
      "jobId": 67890
    }
  }
  ```

* **`resume.bulk_upload_parse.completed`**: Sent when batch processing completes

  ```json theme={null}
  {
    "event": "resume.bulk_upload_parse.completed",
    "timestamp": "2024-01-20T14:45:00Z",
    "companyId": "companyId_1",
    "data": {
      "batchId": 12345,
      "status": "COMPLETED",
      "fileCount": 25,
      "successCount": 23,
      "failedCount": 2,
      "jobId": 67890,
      "error": null,
      "errorCode": null
    }
  }
  ```

  Note: If there are insufficient credits, the `error` and `errorCode` fields will be populated:

  ```json theme={null}
  {
    "event": "resume.bulk_upload_parse.completed",
    "timestamp": "2024-01-20T14:45:00Z",
    "companyId": "companyId_1",
    "data": {
      "batchId": 12345,
      "status": "COMPLETED",
      "fileCount": 25,
      "successCount": 0,
      "failedCount": 25,
      "jobId": 67890,
      "error": "You have insufficient credits to parse the resume.",
      "errorCode": "INSUFFICIENT_CREDITS"
    }
  }
  ```

* **`resume.bulk_upload_parse.failed`**: Sent if batch processing fails
  ```json theme={null}
  {
    "event": "resume.bulk_upload_parse.failed",
    "timestamp": "2024-01-20T14:45:00Z",
    "companyId": "companyId_1",
    "data": {
      "error": "Error message"
    }
  }
  ```

### Error Responses

**Missing resumeURLs**:

```json theme={null}
{
  "error": {
    "code": "MISSING_RESUME_URLS",
    "type": "validation_error",
    "message": "resumeURLs is required in the request body"
  }
}
```

**Invalid resumeURLs format**:

```json theme={null}
{
  "error": {
    "code": "INVALID_RESUME_URLS",
    "type": "validation_error",
    "message": "resumeURLs must be an array of URLs",
    "details": {
      "invalidCount": 1
    }
  }
}
```

**Exceeded maximum resume URLs**:

```json theme={null}
{
  "error": {
    "code": "EXCEEDED_MAX_RESUME_URLS",
    "type": "validation_error",
    "message": "Maximum 5000 resume URLs allowed per request",
    "details": {
      "provided": 6000,
      "maximum": 5000
    }
  }
}
```

**Invalid URL format (non-empty string validation)**:

```json theme={null}
{
  "error": {
    "code": "INVALID_RESUME_URLS",
    "type": "validation_error",
    "message": "All resumeURLs must be non-empty strings",
    "details": {
      "invalidCount": 2
    }
  }
}
```

**Empty resumeURLs array**:

```json theme={null}
{
  "error": {
    "code": "MISSING_RESUME_URLS",
    "type": "validation_error",
    "message": "resumeURLs array cannot be empty"
  }
}
```

**Company not found**:

```json theme={null}
{
  "error": {
    "code": "COMPANY_NOT_FOUND",
    "type": "resource_error",
    "message": "Company not found for this API key"
  }
}
```

**Subscription not active**:

```json theme={null}
{
  "error": {
    "code": "SUBSCRIPTION_NOT_ACTIVE",
    "type": "subscription_error",
    "message": "Your subscription is not active. Please renew to continue."
  }
}
```

## Get Batch Candidates

Retrieve parsed candidates from a batch with pagination.

### `GET /candidates/batch/:batchId`

### Authentication

Requires API key authentication via `Authorization: Bearer YOUR_API_KEY` header.

### Path Parameters

| Parameter | Type    | Description                                         |
| --------- | ------- | --------------------------------------------------- |
| `batchId` | integer | The batch ID returned from the bulk upload endpoint |

### Query Parameters

| Parameter    | Type    | Required | Description                                                       |
| ------------ | ------- | -------- | ----------------------------------------------------------------- |
| `pageNumber` | integer | No       | Page number (default: 1)                                          |
| `perPage`    | integer | No       | Items per page. Must be one of: 10, 20, 40, 80, 100 (default: 10) |

### Example Request

```bash theme={null}
curl -X GET "https://partner-api.taptalent.io/v1/partner/candidates/batch/12345?pageNumber=1&perPage=20" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json"
```

### Example Response

```json theme={null}
{
  "success": true,
  "data": {
    "batchId": 12345,
    "batchStatus": "COMPLETED",
    "total": 45,
    "pageNumber": 1,
    "perPage": 20,
    "hasNextPage": true,
    "candidates": [
      {
        "id": 12345,
        "name": "John Doe",
        "email": "john.doe@example.com",
        "phone": "+1234567890",
        "resumeUrl": "https://storage.example.com/resumes/john-doe.pdf",
        "createdAt": "2024-01-20T14:45:00Z"
      },
      {
        "id": 12346,
        "name": "Jane Smith",
        "email": "jane.smith@example.com",
        "phone": "+0987654321",
        "resumeUrl": "https://storage.example.com/resumes/john-doe.pdf",
        "createdAt": "2024-01-20T14:46:00Z"
      }
    ]
  }
}
```

### Response Fields

| Field              | Type    | Description                                                         |
| ------------------ | ------- | ------------------------------------------------------------------- |
| `success`          | boolean | Indicates if the request was successful                             |
| `data.batchId`     | integer | The batch ID                                                        |
| `data.batchStatus` | string  | Batch processing status (e.g., "PROCESSING", "COMPLETED", "FAILED") |
| `data.total`       | number  | Total number of candidates in the batch                             |
| `data.pageNumber`  | number  | Current page number                                                 |
| `data.perPage`     | number  | Number of items per page                                            |
| `data.hasNextPage` | boolean | Indicates if there are more pages                                   |
| `data.candidates`  | array   | Array of candidate objects                                          |

### Candidate Object Fields

| Field       | Type              | Description                          |
| ----------- | ----------------- | ------------------------------------ |
| `id`        | integer           | Unique candidate identifier          |
| `name`      | string            | Candidate's full name                |
| `email`     | string            | Candidate's email address            |
| `phone`     | string            | Candidate's phone number             |
| `resumeUrl` | string            | URL to the stored resume file        |
| `createdAt` | string (ISO 8601) | Timestamp when candidate was created |

### Error Responses

**Invalid batchId**:

```json theme={null}
{
  "error": {
    "code": "INVALID_BATCH_ID",
    "type": "validation_error",
    "message": "batchId is required"
  }
}
```

**Batch not found**:

```json theme={null}
{
  "error": {
    "code": "BATCH_NOT_FOUND",
    "type": "resource_error",
    "message": "Batch not found"
  }
}
```

**Unauthorized access**:

```json theme={null}
{
  "error": {
    "code": "UNAUTHORIZED_ACCESS",
    "type": "authorization_error",
    "message": "You do not have access to this batch"
  }
}
```

**Invalid perPage value**:

```json theme={null}
{
  "error": {
    "code": "INVALID_PER_PAGE",
    "type": "validation_error",
    "message": "perPage must be one of: 10, 20, 40, 80, 100"
  }
}
```

## Use Cases

### Candidate Search and Filtering

Use the list endpoint to search and filter candidates:

1. **Search by Skills**: Filter candidates by specific skills (e.g., `skills=javascript,react,node.js`)
2. **Filter by Job**: Find candidates associated with specific jobs (`jobIds=12345,12346`)
3. **Filter by Stage**: Get candidates in specific pipeline stages (`stageIds=789,790`)
4. **Search by Contact Info**: Find candidates by email or phone (`candidateEmail=john@example.com`)
5. **Filter by Current Role**: Find candidates with specific job titles or companies (`currentJobTitle=Software Engineer`)

### Candidate Detail Retrieval

Get comprehensive candidate information:

* Retrieve full candidate profile including work experience, education, and certifications
* Access candidate's resume and cover letter
* View candidate's social profiles (LinkedIn, GitHub)
* Get complete candidate history and details

### Bulk Candidate Ingestion

Upload multiple resumes at once to quickly build your candidate database:

1. Collect resume URLs from your ATS or other sources
2. Upload them in batches (up to 5,000 per batch)
3. Receive webhook notifications when processing starts/completes
4. Retrieve parsed candidates using the batch ID

### Resume Parsing Pipeline

Integrate TapTalent's resume parsing into your workflow:

* Upload resumes as they come in
* Receive real-time webhook notifications
* Retrieve parsed candidate data programmatically
* Sync with your internal systems

## Best Practices

### Filtering and Search

* **Use Specific Filters**: Combine multiple filters for precise results (e.g., `skills` + `currentJobTitle`)
* **Pagination**: Use appropriate `perPage` values (10, 20, 40, 80, or 100) based on your needs
* **Search Terms**: Use `searchTerm` for broad text searches across multiple fields
* **Comma-Separated Lists**: For array filters (`jobIds`, `stageIds`, `skills`, `groupIds`), use comma-separated values
* **Case Sensitivity**: Skill searches are case-insensitive, but other text filters may be case-sensitive

### Candidate Details

* **Cache Results**: Cache candidate details to reduce API calls for frequently accessed candidates
* **Error Handling**: Always handle 404 errors for candidates that may have been deleted
* **Field Access**: All miscellaneous fields (educations, workExperiences, etc.) are flattened to the top level

### Batch Size

* You can upload up to 5,000 resume URLs in a single request
* For very large uploads (1,000+ resumes), consider splitting into multiple requests to better track progress
* Use batches of 50-500 resumes for optimal balance between speed and tracking

### Error Handling

* Handle webhook events for batch status updates
* Implement retry logic for failed uploads
* Monitor batch status and handle failures gracefully

### Pagination

* Use appropriate `perPage` values (10, 20, 40, 80, or 100)
* Check `hasNextPage` to determine if more data is available
* Implement pagination loops to retrieve all candidates
* Note that list endpoint uses 0-indexed pages (`pageNumber=0` for first page)

### Webhook Integration

* Set up webhook URL to receive batch status updates
* Handle both success and failure webhook events
* Use webhooks to trigger downstream processing

## Bulk Fetch Candidates

Fetch multiple candidates by their IDs in a single request.

### `POST /candidates/bulk-fetch`

### Authentication

Requires API key authentication via `Authorization: Bearer YOUR_API_KEY` header.

### Request Body

| Field          | Type                     | Required | Description                                                   |
| -------------- | ------------------------ | -------- | ------------------------------------------------------------- |
| `candidateIds` | array of strings/numbers | Yes      | Array of candidate IDs to fetch. Maximum 100 IDs per request. |

### Request Body Example

```json theme={null}
{
  "candidateIds": [
    12345,
    12346,
    12347
  ]
}
```

### Example Request

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/candidates/bulk-fetch" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "candidateIds": [
      12345,
      12346
    ]
  }'
```

### Example Response

```json theme={null}
{
  "status": "success",
  "data": [
    {
      "id": 12345,
      "firstName": "John",
      "lastName": "Doe",
      "email": "john.doe@example.com",
      "phone": "+1234567890",
      "currentJobTitle": "Software Engineer",
      "currentCompany": "Tech Corp",
      "city": "San Francisco",
      "country": "United States",
      "skills": ["JavaScript", "React", "Node.js"],
      "resume": "https://storage.example.com/resumes/john-doe.pdf",
      "majors": ["Computer Science"],
      "summary": "Experienced software engineer...",
      "languages": ["English"],
      "educations": [
        {
          "degree": "Bachelor's",
          "field": "Computer Science",
          "institution": "University"
        }
      ],
      "workExperiences": [
        {
          "title": "Software Engineer",
          "company": "Tech Corp",
          "duration": "2 years"
        }
      ],
      "projectExperiences": [],
      "certifications": [],
      "githubUrl": "https://github.com/johndoe",
      "linkedin": "https://linkedin.com/in/johndoe"
    }
  ],
  "invalidCandidateIds": [12347]
}
```

### Response Fields

| Field                 | Type             | Description                                                                       |
| --------------------- | ---------------- | --------------------------------------------------------------------------------- |
| `status`              | string           | Response status ("success")                                                       |
| `data`                | array            | Array of candidate objects                                                        |
| `invalidCandidateIds` | array (optional) | Array of candidate IDs that were not found (only included if any IDs are invalid) |

### Validation Rules

* `candidateIds` must be provided and cannot be empty
* `candidateIds` must be an array
* Maximum 100 candidate IDs per request
* Each candidate ID must be a valid non-empty string or number

### Error Responses

**Missing candidateIds**:

```json theme={null}
{
  "error": {
    "code": "MISSING_CANDIDATE_IDS",
    "type": "validation_error",
    "message": "candidateIds is required in the request body"
  }
}
```

**Invalid candidateIds format**:

```json theme={null}
{
  "error": {
    "code": "INVALID_CANDIDATE_IDS",
    "type": "validation_error",
    "message": "candidateIds must be an array",
    "details": {
      "invalidCount": 1
    }
  }
}
```

**Exceeded maximum**:

```json theme={null}
{
  "error": {
    "code": "EXCEEDED_MAX_CANDIDATES",
    "type": "validation_error",
    "message": "Maximum 100 candidateIds allowed per request",
    "details": {
      "provided": 150,
      "maximum": 100
    }
  }
}
```

## Next Steps

* Set up [Webhooks](/webhooks/overview) to receive batch status updates
* Review [Integration Notes](/integration-notes/overview) for best practices
* Explore other [API endpoints](/api-reference/overview)
