> ## 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.

# Custom Fields

> API endpoints for managing custom fields and their values for jobs and candidates

The Custom Fields API allows you to create, read, update, and delete custom field definitions and their values for jobs and candidates. Custom fields enable you to store additional structured data beyond the standard fields.

## Overview

Custom fields consist of two parts:

1. **Custom Field Definitions**: The field templates that define what type of data can be stored (e.g., "Preferred Communication Method" as a select field with options, "Tentative Closing Date" as a date field )
2. **Custom Field Values**: The actual values stored for specific jobs or candidates (e.g., "Email" for a particular candidate)

### Custom Field Definitions

Each custom field definition has:

* **Entity Type**: Either `candidate` or `job` (determines which entity the field applies to)
* **Field Type**: The data type (text, number, date, select, multi-select, checkbox, textarea)
* **Field Label**: The display name for the field
* **Parent Section**: The section where the field appears in the UI
* **Options**: For select/multi-select fields, the available options

### Custom Field Values

Custom field values link field definitions to specific entities with actual data. Values are stored in a normalized table format:

* **Text/Textarea/Select**: Stored as strings (JSON string for multi-select arrays)
* **Number**: Stored as decimals
* **Date**: Stored as DATEONLY (YYYY-MM-DD format)
* **Checkbox**: Stored as booleans

***

## Custom Field Definitions

This section covers managing custom field definitions (the field templates).

## Get All Custom Fields

Retrieve all custom fields for your company, optionally filtered by entity type.

### `GET /custom-fields`

### Authentication

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

### Query Parameters

| Parameter    | Type   | Required | Description                                 |
| ------------ | ------ | -------- | ------------------------------------------- |
| `entityType` | string | No       | Filter by entity type: `candidate` or `job` |

### Example Request

```bash theme={null}
# Get all custom fields
curl -X GET "https://partner-api.taptalent.io/v1/partner/custom-fields" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

# Get only candidate custom fields
curl -X GET "https://partner-api.taptalent.io/v1/partner/custom-fields?entityType=candidate" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

# Get only job custom fields
curl -X GET "https://partner-api.taptalent.io/v1/partner/custom-fields?entityType=job" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
```

### Example Response

```json theme={null}
{
  "status": "success",
  "data": [
    {
      "id": "123",
      "entityType": "candidate",
      "fieldLabel": "Preferred Communication Method",
      "fieldType": "select",
      "options": ["Email", "Phone", "SMS", "WhatsApp"],
      "description": "How the candidate prefers to be contacted",
      "parentSection": "Personal Details",
      "createdAt": "2024-01-15T10:00:00.000Z",
      "updatedAt": "2024-01-15T10:00:00.000Z"
    },
    {
      "id": "124",
      "entityType": "job",
      "fieldLabel": "Internal Priority",
      "fieldType": "text",
      "options": null,
      "description": "Internal priority level for the job",
      "parentSection": "Job Overview",
      "createdAt": "2024-01-16T10:00:00.000Z",
      "updatedAt": "2024-01-16T10:00:00.000Z"
    }
  ]
}
```

## Get Custom Field by ID

Retrieve a specific custom field by its ID.

### `GET /custom-fields/:customFieldId`

### Authentication

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

### Path Parameters

| Parameter       | Type   | Description                               |
| --------------- | ------ | ----------------------------------------- |
| `customFieldId` | string | The unique identifier of the custom field |

### Example Request

```bash theme={null}
curl -X GET "https://partner-api.taptalent.io/v1/partner/custom-fields/123" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
```

### Example Response

```json theme={null}
{
  "status": "success",
  "data": {
    "id": "123",
    "entityType": "candidate",
    "fieldLabel": "Preferred Communication Method",
    "fieldType": "select",
    "options": ["Email", "Phone", "SMS", "WhatsApp"],
    "description": "How the candidate prefers to be contacted",
    "parentSection": "Personal Details",
    "createdAt": "2024-01-15T10:00:00.000Z",
    "updatedAt": "2024-01-15T10:00:00.000Z"
  }
}
```

### Error Responses

**Custom field not found**:

```json theme={null}
{
  "error": {
    "code": "CUSTOM_FIELD_NOT_FOUND",
    "type": "resource_error",
    "message": "Custom field not found"
  }
}
```

**Unauthorized access**:

```json theme={null}
{
  "error": {
    "code": "PERMISSION_DENIED",
    "type": "authorization_error",
    "message": "You are not authorized to access this custom field"
  }
}
```

## Create Custom Field

Create a new custom field for jobs or candidates.

### `POST /custom-fields`

### Authentication

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

### Request Body

| Field           | Type   | Required    | Description                                                                            |
| --------------- | ------ | ----------- | -------------------------------------------------------------------------------------- |
| `entityType`    | string | Yes         | Entity type: `candidate` or `job`                                                      |
| `fieldLabel`    | string | Yes         | Display name for the field                                                             |
| `fieldType`     | string | Yes         | Field type: `text`, `number`, `date`, `select`, `multi-select`, `checkbox`, `textarea` |
| `parentSection` | string | No          | Section where field appears (see [Parent Sections](#parent-sections))                  |
| `options`       | array  | Conditional | Required for `select` and `multi-select` types. Array of option strings                |
| `description`   | string | No          | Description/help text for the field                                                    |

### Field Types

| Field Type     | Description            | Options Required |
| -------------- | ---------------------- | ---------------- |
| `text`         | Single-line text input | No               |
| `textarea`     | Multi-line text input  | No               |
| `number`       | Numeric input          | No               |
| `date`         | Date picker            | No               |
| `checkbox`     | Boolean checkbox       | No               |
| `select`       | Single-select dropdown | Yes              |
| `multi-select` | Multi-select dropdown  | Yes              |

### Parent Sections

#### For Candidates (`entityType: "candidate"`)

* `Personal Details`
* `Social Contacts`
* `Experience`
* `Education`
* `Skills`
* `Miscellaneous`

#### For Jobs (`entityType: "job"`)

* `Job Overview`
* `Job Description`
* `Job Pipeline Stages`
* `Location`
* `Revenue Details`
* `Client Company Details`
* `Salary Details`
* `Candidate Requirements`
* `Candidate Form Requirements`
* `Screening Questions`

### Example Requests

#### Create a Text Field

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/custom-fields" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "candidate",
    "fieldLabel": "Employee ID",
    "fieldType": "text",
    "parentSection": "Personal Details",
    "description": "Internal employee identifier"
  }'
```

#### Create a Select Field

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/custom-fields" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "candidate",
    "fieldLabel": "Preferred Communication Method",
    "fieldType": "select",
    "parentSection": "Personal Details",
    "options": ["Email", "Phone", "SMS", "WhatsApp"],
    "description": "How the candidate prefers to be contacted"
  }'
```

#### Create a Multi-Select Field

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/custom-fields" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "job",
    "fieldLabel": "Required Certifications",
    "fieldType": "multi-select",
    "parentSection": "Candidate Requirements",
    "options": ["AWS Certified", "PMP", "CISSP", "CPA", "CFA"],
    "description": "List of required professional certifications"
  }'
```

#### Create a Number Field

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/custom-fields" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "job",
    "fieldLabel": "Budget Allocation",
    "fieldType": "number",
    "parentSection": "Job Overview",
    "description": "Budget allocated for this position in USD"
  }'
```

#### Create a Date Field

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/custom-fields" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "candidate",
    "fieldLabel": "Availability Start Date",
    "fieldType": "date",
    "parentSection": "Personal Details",
    "description": "Date when candidate is available to start"
  }'
```

#### Create a Checkbox Field

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/custom-fields" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "job",
    "fieldLabel": "Remote Work Allowed",
    "fieldType": "checkbox",
    "parentSection": "Job Overview",
    "description": "Whether remote work is allowed for this position"
  }'
```

### Example Response

```json theme={null}
{
  "status": "success",
  "message": "Custom field created successfully",
  "data": {
    "id": "123",
    "entityType": "candidate",
    "fieldLabel": "Preferred Communication Method",
    "fieldType": "select",
    "options": ["Email", "Phone", "SMS", "WhatsApp"],
    "description": "How the candidate prefers to be contacted",
    "parentSection": "Personal Details",
    "createdAt": "2024-01-15T10:00:00.000Z",
    "updatedAt": "2024-01-15T10:00:00.000Z"
  }
}
```

### Error Responses

**Missing required fields**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Missing required fields: entityType, fieldLabel, and fieldType are required"
  }
}
```

**Invalid entity type**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Invalid entityType. Must be one of: candidate, job"
  }
}
```

**Invalid field type**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Invalid fieldType. Must be one of: text, number, date, select, multi-select, checkbox, textarea"
  }
}
```

**Missing options for select/multi-select**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Options array is required and must not be empty for select/multi-select field types"
  }
}
```

## Update Custom Field

Update an existing custom field. Note: `fieldType` cannot be changed after creation.

### `PUT /custom-fields/:customFieldId`

### Authentication

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

### Path Parameters

| Parameter       | Type   | Description                                         |
| --------------- | ------ | --------------------------------------------------- |
| `customFieldId` | string | The unique identifier of the custom field to update |

### Request Body

All fields are optional - only include fields you want to update.

| Field           | Type   | Required | Description                                      |
| --------------- | ------ | -------- | ------------------------------------------------ |
| `fieldLabel`    | string | No       | Updated display name                             |
| `parentSection` | string | No       | Updated parent section                           |
| `options`       | array  | No       | Updated options (for select/multi-select fields) |
| `description`   | string | No       | Updated description                              |

**Note**: `fieldType` and `entityType` cannot be updated after creation.

### Example Request

```bash theme={null}
curl -X PUT "https://partner-api.taptalent.io/v1/partner/custom-fields/123" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "fieldLabel": "Updated Communication Preference",
    "options": ["Email", "Phone", "SMS", "WhatsApp", "LinkedIn"],
    "description": "Updated description"
  }'
```

### Example Response

```json theme={null}
{
  "status": "success",
  "message": "Custom field updated successfully",
  "data": {
    "id": "123",
    "entityType": "candidate",
    "fieldLabel": "Updated Communication Preference",
    "fieldType": "select",
    "options": ["Email", "Phone", "SMS", "WhatsApp", "LinkedIn"],
    "description": "Updated description",
    "parentSection": "Personal Details",
    "createdAt": "2024-01-15T10:00:00.000Z",
    "updatedAt": "2024-01-15T11:00:00.000Z"
  }
}
```

### Error Responses

**Custom field not found**:

```json theme={null}
{
  "error": {
    "code": "CUSTOM_FIELD_NOT_FOUND",
    "type": "resource_error",
    "message": "Custom field not found"
  }
}
```

**No fields to update**:

```json theme={null}
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "At least one field (fieldLabel, parentSection, options, or description) must be provided for update"
  }
}
```

## Delete Custom Field

Delete a custom field. This will remove the field definition, but existing field values on jobs/candidates will remain.

### `DELETE /custom-fields/:customFieldId`

### Authentication

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

### Path Parameters

| Parameter       | Type   | Description                                         |
| --------------- | ------ | --------------------------------------------------- |
| `customFieldId` | string | The unique identifier of the custom field to delete |

### Example Request

```bash theme={null}
curl -X DELETE "https://partner-api.taptalent.io/v1/partner/custom-fields/123" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
```

### Example Response

```json theme={null}
{
  "status": "success",
  "message": "Custom field deleted successfully"
}
```

### Error Responses

**Custom field not found**:

```json theme={null}
{
  "error": {
    "code": "CUSTOM_FIELD_NOT_FOUND",
    "type": "resource_error",
    "message": "Custom field not found"
  }
}
```

**Unauthorized access**:

```json theme={null}
{
  "error": {
    "code": "PERMISSION_DENIED",
    "type": "authorization_error",
    "message": "You can only delete custom fields for your company"
  }
}
```

## Limitations and Best Practices

### Limitations

1. **Field Type Immutability**: Once a custom field is created, its `fieldType` cannot be changed. You must delete and recreate the field if you need a different type.

2. **Entity Type Immutability**: The `entityType` (candidate or job) cannot be changed after creation.

3. **Options for Select Fields**: Select and multi-select fields require at least one option. Options cannot be empty.

4. **Company Isolation**: Custom fields are company-specific. You can only access and modify custom fields that belong to your company.

### Best Practices

1. **Naming**: Use clear, descriptive field labels that indicate the purpose of the field.

2. **Parent Sections**: Choose appropriate parent sections to organize fields logically in the UI.

3. **Options**: For select/multi-select fields, provide comprehensive and mutually exclusive options.

4. **Descriptions**: Include helpful descriptions to guide users on how to use the field.

5. **Field Types**: Choose the appropriate field type for your data:
   * Use `text` for short, single-line inputs
   * Use `textarea` for longer, multi-line text
   * Use `number` for numeric values
   * Use `date` for date values
   * Use `select` when users should choose one option
   * Use `multi-select` when users can choose multiple options
   * Use `checkbox` for boolean yes/no values

6. **Planning**: Plan your custom fields carefully since field types cannot be changed after creation.

***

## Custom Field Values

This section covers managing the actual values stored for custom fields on jobs and candidates. Values are stored in a normalized table for efficient querying and filtering.

### Get Custom Field Values by Entity

Retrieve all custom field values for a specific candidate or job.

#### `GET /custom-field-values`

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

**Query Parameters**:

| Parameter          | Type    | Required | Description                                                              |
| ------------------ | ------- | -------- | ------------------------------------------------------------------------ |
| `entityType`       | string  | Yes      | Entity type: `candidate` or `job`                                        |
| `entityId`         | integer | Yes      | The ID of the candidate or job                                           |
| `parentEntityType` | string  | No       | Filter by parent entity type (e.g., `work_experience` for nested fields) |
| `parentEntityId`   | integer | No       | Filter by parent entity ID (epoch timestamp for work experiences)        |

**Example Request**:

```bash theme={null}
# Get all custom field values for a candidate
curl -X GET "https://partner-api.taptalent.io/v1/partner/custom-field-values?entityType=candidate&entityId=12345" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
```

**Example Response**:

```json theme={null}
{
  "status": "success",
  "data": [
    {
      "id": 1001,
      "customFieldId": 58,
      "entityType": "candidate",
      "entityId": 12345,
      "value": "Email",
      "parentEntityType": null,
      "parentEntityId": null,
      "createdAt": "2024-01-15T10:00:00.000Z",
      "updatedAt": "2024-01-15T10:00:00.000Z"
    }
  ]
}
```

### Get Custom Field Value by ID

Retrieve a specific custom field value by its ID.

#### `GET /custom-field-values/:valueId`

**Path Parameters**: `valueId` (integer) - The unique identifier of the custom field value

**Example Request**:

```bash theme={null}
curl -X GET "https://partner-api.taptalent.io/v1/partner/custom-field-values/1001" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
```

### Create or Update Custom Field Value

Create a new custom field value or update an existing one (upsert operation).

#### `POST /custom-field-values`

**Request Body**:

| Field              | Type    | Required | Description                                                    |
| ------------------ | ------- | -------- | -------------------------------------------------------------- |
| `customFieldId`    | integer | Yes      | The ID of the custom field                                     |
| `entityType`       | string  | Yes      | Entity type: `candidate` or `job`                              |
| `entityId`         | integer | Yes      | The ID of the candidate or job                                 |
| `value`            | mixed   | Yes      | The value to store (type depends on field type)                |
| `parentEntityType` | string  | No       | Parent entity type (e.g., `work_experience` for nested fields) |
| `parentEntityId`   | integer | No       | Parent entity ID (epoch timestamp for work experiences)        |

**Value Types by Field Type**:

| Field Type     | Value Format      | Example                    |
| -------------- | ----------------- | -------------------------- |
| `text`         | string            | `"Some text"`              |
| `textarea`     | string            | `"Long text content"`      |
| `number`       | number            | `42.5`                     |
| `date`         | string (ISO date) | `"2024-01-15"`             |
| `checkbox`     | boolean           | `true`                     |
| `select`       | string            | `"Option 1"`               |
| `multi-select` | array of strings  | `["Option 1", "Option 2"]` |

**Example Request**:

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/custom-field-values" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "customFieldId": 58,
    "entityType": "candidate",
    "entityId": 12345,
    "value": "Email"
  }'
```

### Bulk Create or Update Custom Field Values

Create or update multiple custom field values in a single request.

#### `POST /custom-field-values/bulk`

**Request Body**:

| Field        | Type    | Required | Description                                                                                            |
| ------------ | ------- | -------- | ------------------------------------------------------------------------------------------------------ |
| `entityType` | string  | Yes      | Entity type: `candidate` or `job`                                                                      |
| `entityId`   | integer | Yes      | The ID of the candidate or job                                                                         |
| `values`     | array   | Yes      | Array of value objects with `customFieldId`, `value`, and optional `parentEntityType`/`parentEntityId` |

**Example Request**:

```bash theme={null}
curl -X POST "https://partner-api.taptalent.io/v1/partner/custom-field-values/bulk" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "entityType": "candidate",
    "entityId": 12345,
    "values": [
      {"customFieldId": 58, "value": "Email"},
      {"customFieldId": 59, "value": ["Option 1", "Option 2"]}
    ]
  }'
```

### Delete Custom Field Value

Delete a specific custom field value by its ID.

#### `DELETE /custom-field-values/:valueId`

**Example Request**:

```bash theme={null}
curl -X DELETE "https://partner-api.taptalent.io/v1/partner/custom-field-values/1001" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
```

### Delete All Custom Field Values for an Entity

Delete all custom field values for a specific candidate or job.

#### `DELETE /custom-field-values/entity/:entityType/:entityId`

**Query Parameters**: Optional `parentEntityType` and `parentEntityId` to filter by parent entity

**Example Request**:

```bash theme={null}
curl -X DELETE "https://partner-api.taptalent.io/v1/partner/custom-field-values/entity/candidate/12345" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
```

***

## Additional Notes

### Value Storage Details

* **Text/Textarea/Select**: Stored as strings in the `value` column
* **Multi-select**: Stored as JSON stringified arrays (e.g., `["Option 1", "Option 2"]`)
* **Number**: Stored in the `valueNumber` column as decimals
* **Date**: Stored in the `valueDate` column as DATEONLY (format: `YYYY-MM-DD`)
* **Checkbox**: Stored in the `valueBoolean` column as booleans

### Nested Fields

Custom fields can be nested within work experiences. When setting values for nested fields:

* Set `parentEntityType` to `"work_experience"`
* Set `parentEntityId` to the unique ID of the work experience (typically an epoch timestamp)

### Upsert Behavior

The create/update endpoint (`POST /custom-field-values`) performs an upsert operation:

* If a value already exists for the given `customFieldId`, `entityType`, `entityId`, and `parentEntityId`, it will be updated
* If no value exists, a new one will be created

### Alternative: Using Custom Fields in Job/Candidate APIs

You can also set custom field values when creating or updating jobs and candidates using the `customFields` object:

```json theme={null}
{
  "customFields": {
    "123": "Some value",
    "456": ["Option 1", "Option 2"],
    "789": true
  }
}
```

Where the keys are the custom field IDs and the values match the field type. See the [Jobs API](./jobs.mdx) and [Candidates API](./candidates.mdx) documentation for details.

### Custom Fields in Job Candidate Responses

When retrieving candidates via the Job Candidates API (e.g., `GET /job-candidates/stage/:stageId/candidates` or `POST /job-candidates/bulk-fetch`), custom fields are returned in an enriched format that includes field labels and parent sections:

```json theme={null}
{
  "customFields": {
    "13": {
      "label": "Preferred Communication Channel",
      "value": "Email",
      "parentSection": "Personal Details"
    },
    "14": {
      "label": "Availability Start Date",
      "value": "2024-02-01",
      "parentSection": "Personal Details"
    }
  }
}
```

This format provides:

* **`label`**: The display name of the custom field (from the field definition)
* **`value`**: The actual value (type depends on field type: string, number, date, boolean, or array)
* **`parentSection`**: The section where the field appears in the UI

This enriched format makes it easier to display custom fields in your application without needing to fetch field definitions separately. Note that the `id` and `entityType` are not included in the nested objects, as they are already represented by the key (customFieldId) and context.
