Skip to main content
The Job Candidates API allows you to manage candidates that are associated with specific jobs. This includes bulk fetching job candidates and uploading resumes directly to jobs.
Understanding Job Criteria and Candidate Matching: When you upload resumes to a job or add candidates, TapTalent’s AI automatically evaluates each candidate against the job’s criterionDetails (job requirements). The AI generates a profile match score and detailed matching information based on how well candidates meet your “Must Have”, “Nice to Have”, and “Bonus” criteria. See the Job Criteria section in the Jobs API documentation for details on how to set up effective job criteria.

Bulk Fetch Job Candidates

Fetch multiple job candidates by their IDs in a single request. This returns candidates with their job-specific information including AI matching scores and evaluation status.

POST /job-candidates/bulk-fetch

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Request Body

FieldTypeRequiredDescription
jobCandidateIdsarray of strings/numbersYesArray of job candidate IDs to fetch. Maximum 100 IDs per request.

Request Body Example

{
  "jobCandidateIds": [
    12345,
    12346,
    12347
  ]
}

Example Request

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

Example Response

{
  "status": "success",
  "data": [
    {
      "id": 12345,
      "jobId": 12345,
      "candidateId": 12345,
      "profileMatchScore": 85,
      "evaluationStatus": "PENDING",
      "criteriaMatches": {
        "skills": 90,
        "experience": 80,
        "education": 75
      },
      "recommendToRecruitingFirm": true,
      "aiSummary": "Strong candidate with relevant experience...",
      "candidate_details": {
        "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"
      },
      "customFields": {
        "13": {
          "label": "Preferred Communication Channel",
          "value": "Email",
          "parentSection": "Personal Details"
        }
      }
    }
  ]
}

Response Fields

FieldTypeDescription
statusstringResponse status (“success”)
dataarrayArray of job candidate objects

Job Candidate Object Fields

FieldTypeDescription
idintegerJob candidate ID
jobIdintegerAssociated job ID
candidateIdintegerCandidate ID
profileMatchScorenumberAI-generated profile match score (0-100). This score is calculated based on how well the candidate meets the job’s criterionDetails. Higher scores indicate better matches.
evaluationStatusstringEvaluation status (e.g., “PENDING”, “APPROVED”, “REJECTED”)
criteriaMatchesobjectBreakdown of how well the candidate matches each job criterion. Shows match percentages for different aspects like skills, experience, and education.
recommendToRecruitingFirmbooleanWhether candidate is recommended based on AI analysis of job criteria
aiSummarystringAI-generated summary explaining why the candidate is a good (or poor) match for the job based on the criteria
candidate_detailsobjectFull candidate details (see candidate object structure)
customFieldsobjectCustom field values for the candidate, formatted as { customFieldId: { label, value, parentSection } }. Only included if custom field values exist.

How Profile Match Scores Work

The profileMatchScore is calculated by evaluating the candidate’s resume against the job’s criterionDetails:
  • “Must Have” criteria are weighted most heavily - candidates missing these will have significantly lower scores
  • “Nice to Have” criteria contribute to the score but won’t disqualify candidates
  • “Bonus” criteria add points for exceptional candidates but don’t penalize those without them
For example:
  • A candidate meeting all “Must Have” criteria and most “Nice to Have” criteria might score 85-95
  • A candidate missing a “Must Have” criterion might score 40-60, even if they meet other criteria
  • A candidate meeting all criteria including “Bonus” items might score 95-100

Validation Rules

  • jobCandidateIds must be provided and cannot be empty
  • jobCandidateIds must be an array
  • Maximum 100 job candidate IDs per request
  • Each job candidate ID must be a valid non-empty string or number

Error Responses

Missing jobCandidateIds:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "jobCandidateIds is required and must be a non-empty array."
  }
}
Exceeded maximum:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "jobCandidateIds must not exceed 100 items."
  }
}

Rescore Job Candidates

Rescore existing job candidates against the job’s current criteria. Use this when you have updated a job’s requirements and want to refresh profile match scores for candidates who have already applied.
  • Maximum 250 candidates per request.
  • The endpoint returns immediately. You receive a webhook when rescoring completes or fails (e.g. insufficient credits when the job runs).

POST /job-candidates/rescore

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Request Body

FieldTypeRequiredDescription
jobIdintegerYesThe job whose current criteria to use for rescoring.
jobCandidateIdsarray of integersNoSpecific job candidate IDs to rescore. If omitted, all candidates for the job (or in the given stage) are rescored, up to the max limit.
stageIdintegerNoIf provided, only candidates in this stage are rescored. The stage must belong to the job’s pipeline.

Request Body Example

{
  "jobId": 12345
}

Request Body Example (by stage)

{
  "jobId": 12345,
  "stageId": 67
}

Request Body Example (specific candidates)

{
  "jobId": 12345,
  "jobCandidateIds": [101, 102, 103]
}

Example Request

curl -X POST "https://partner-api.taptalent.io/v1/partner/job-candidates/rescore" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{"jobId": 12345}'

Example Response (202 Accepted)

{
  "status": "accepted",
  "data": {
    "rescoreId": "rescore_12345_1699123456789",
    "jobId": 12345,
    "totalEligible": 50,
    "totalQueued": 50,
    "message": "Rescore queued. You will receive a webhook when it completes. See the API documentation for how to fetch updated scores."
  }
}
When the number of candidates accepted is limited by your credit balance, the response may include creditsAvailable.

Response Fields

FieldTypeDescription
data.rescoreIdstringUnique identifier for this rescore run. Use it to fetch rescore status or updated candidates.
data.jobIdintegerThe job that is being rescored.
data.totalEligiblenumberTotal candidates that matched your request (job, stage, or IDs).
data.totalQueuednumberNumber of candidates accepted for rescoring in this request.
data.creditsAvailablenumberPresent only when limited by credits: balance at request time.

Validation Rules

  • jobId is required and must belong to your company.
  • jobCandidateIds must not exceed 250 items.
  • Request fails with 402 if you have no scoring credits.

Error: Insufficient credits (402)

{
  "error": {
    "code": "INSUFFICIENT_CREDITS",
    "type": "validation_error",
    "message": "Insufficient scoring credits. Please add credits to rescore candidates."
  }
}

Webhook: job.candidates.rescored

When rescoring completes or fails, a webhook is sent to your configured URL with event job.candidates.rescored. If there are no credits at that time, the rescore is marked failed and you receive a webhook with status: "failed" and an error reason (e.g. “Insufficient scoring credits”). Payload:
FieldTypeDescription
jobIdintegerThe job that was rescored.
rescoreIdstringSame as the rescoreId from the API response.
statusstring"completed" or "failed".
jobCandidateIdsarray of integersJob candidate IDs included in this rescore. Use to fetch updated scores.
totalEligiblenumberTotal candidates that matched your request.
totalRequestednumberNumber of candidates in this rescore.
totalProcessednumberNumber successfully rescored.
totalFailednumberNumber that failed.
cappedByCreditsbooleanWhen true, some candidates were not processed due to credit limit.
errorsarrayList of error objects. Each has at least reason (e.g. "Insufficient scoring credits"). May include jobCandidateId for per-candidate failures.

After receiving the webhook

Scores are stored on each job candidate. See the API reference for endpoints to fetch candidates by rescoreId or by job/list; use the webhook payload to know when rescoring finished and which IDs were included. Example webhook payload (success):
{
  "event": "job.candidates.rescored",
  "timestamp": "2024-11-05T12:00:00.000Z",
  "companyId": 1,
  "data": {
    "jobId": 12345,
    "rescoreId": "rescore_12345_1699123456789",
    "status": "completed",
    "jobCandidateIds": [101, 102, 103, 104, 105],
    "totalEligible": 5,
    "totalRequested": 5,
    "totalProcessed": 5,
    "totalFailed": 0,
    "cappedByCredits": false,
    "errors": []
  }
}

Get candidates by rescoreId

Return candidates from a rescore with their updated scores. Use the rescoreId from the API response or webhook.

GET /job-candidates/rescore/:rescoreId/candidates

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Path Parameters

ParameterTypeRequiredDescription
rescoreIdstringYesThe rescore ID from the 202 response or webhook (e.g. rescore_12345_1699123456789).

Example Request

curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/rescore/rescore_12345_1699123456789/candidates" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

Example Response

Same structure as Bulk Fetch Job Candidates: { "status": "success", "data": [ ... ] } with updated scores. Max 250 per rescore.

Error Responses

Rescore not found (404):
{
  "error": {
    "code": "RESCORE_NOT_FOUND",
    "type": "resource_error",
    "message": "Rescore not found"
  }
}

Get rescore status by rescoreId

Fetch status and summary for a rescore using its rescoreId.

GET /job-candidates/rescore/:rescoreId

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Path Parameters

ParameterTypeRequiredDescription
rescoreIdstringYesThe rescore ID returned in the 202 response and in the webhook payload (e.g. rescore_12345_1699123456789).

Example Request

curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/rescore/rescore_12345_1699123456789" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

Example Response

The response includes only partner-facing fields (no internal IDs or timestamps).
{
  "status": "success",
  "data": {
    "rescoreId": "rescore_12345_1699123456789",
    "jobId": 12345,
    "status": "completed",
    "totalEligible": 50,
    "totalRequested": 50,
    "totalProcessed": 50,
    "totalFailed": 0,
    "jobCandidateIds": [101, 102, 103],
    "cappedByCredits": false,
    "errors": [],
    "completedAt": "2024-11-05T12:05:00.000Z"
  }
}

Response Fields

FieldTypeDescription
data.rescoreIdstringUnique rescore run ID.
data.jobIdintegerJob that was rescored.
data.statusstring"completed", "failed", or "queued" (still running).
data.totalEligiblenumberCandidates that matched the rescore request.
data.totalRequestednumberCandidates in this rescore.
data.totalProcessednumberCandidates successfully rescored.
data.totalFailednumberCandidates that failed.
data.jobCandidateIdsarrayJob candidate IDs in this rescore.
data.cappedByCreditsbooleanWhether processing was limited by scoring credits.
data.errorsarrayError objects (e.g. { "reason": "Insufficient scoring credits" }). Empty when none.
data.completedAtstring (ISO 8601) or nullWhen the rescore finished.

Error Responses

Rescore not found (404):
{
  "error": {
    "code": "RESCORE_NOT_FOUND",
    "type": "resource_error",
    "message": "Rescore not found"
  }
}
(Returned when the rescoreId does not exist or belongs to another company.)

Bulk Upload Resumes to Job

Upload multiple resumes for parsing and associate them with a specific job.

POST /job-candidates/bulk/resume

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Request Body

FieldTypeRequiredDescription
jobIdintegerYesThe job ID to associate the resumes with
resumeURLsarray of stringsYesArray of publicly accessible URLs pointing to resume files (PDF, DOC, DOCX). Maximum 5,000 resumes per request.

Request Body Example

{
  "jobId": 12345,
  "resumeURLs": [
    "https://example.com/resumes/john-doe.pdf",
    "https://example.com/resumes/jane-smith.docx"
  ]
}

Example Request

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

Example Response

{
  "success": true,
  "data": {
    "batchId": 12345,
    "fileCount": 2,
    "jobId": 12345
  }
}

Response Fields

FieldTypeDescription
successbooleanIndicates if the request was successful
data.batchIdintegerUnique identifier for this batch. Use this to retrieve candidates later.
data.fileCountnumberNumber of resumes in the batch
data.jobIdintegerThe job ID the resumes are associated with

Validation Rules

  • jobId must be provided and must be a valid integer
  • 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
  • The job must exist and belong to your company

Webhook Events

When you upload resumes to a job, webhook events are triggered:
  • resume.bulk_upload_parse.started: Sent when batch processing starts
    {
      "event": "resume.bulk_upload_parse.started",
      "timestamp": "2024-01-20T14:45:00Z",
      "companyId": "companyId_1",
      "data": {
        "batchId": 12345,
        "fileCount": 2,
        "jobId": 12345
      }
    }
    
  • resume.bulk_upload_parse.completed: Sent when batch processing completes
    {
      "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": 12345
      }
    }
    
  • resume.bulk_upload_parse.failed: Sent if batch processing fails
    {
      "event": "resume.bulk_upload_parse.failed",
      "timestamp": "2024-01-20T14:45:00Z",
      "companyId": "companyId_1",
      "data": {
        "error": "Error message",
        "jobId": 12345
      }
    }
    

Error Responses

Missing jobId:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Job ID is required"
  }
}
Job not found:
{
  "error": {
    "code": "JOB_NOT_FOUND",
    "type": "validation_error",
    "message": "Job not found"
  }
}
Permission denied:
{
  "error": {
    "code": "PERMISSION_DENIED",
    "type": "validation_error",
    "message": "You are not authorized to access this job"
  }
}
Exceeded maximum resume URLs:
{
  "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:
{
  "error": {
    "code": "INVALID_RESUME_URLS",
    "type": "validation_error",
    "message": "All resumeURLs must be non-empty strings",
    "details": {
      "invalidCount": 2
    }
  }
}

Get Candidates for a Job

Retrieve all candidates associated with a specific job with pagination, filtering, and sorting options.

GET /job-candidates/job/:jobId/candidates

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Path Parameters

ParameterTypeRequiredDescription
jobIdintegerYesThe unique identifier of the job

Query Parameters

ParameterTypeRequiredDescription
pageintegerNoPage number (default: 1)
perPageintegerNoItems per page. Must be one of: 10, 20, 40, 80, 100 (default: 20)
stageIdintegerNoFilter candidates by pipeline stage ID
resumeScoreMinnumberNoMinimum resume/AI match score (0-100). Filter candidates with score >= this value
resumeScoreMaxnumberNoMaximum resume/AI match score (0-100). Filter candidates with score <= this value
orderColumnstringNoColumn to sort by. Valid values: createdAt, firstName. Default: createdAt
orderBystringNoSort order. Valid values: ASC, DESC. Default: DESC
excludeRejectedbooleanNoExclude rejected candidates from results. Set to true to filter out rejected candidates. Default: false

Example Request

curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/job/12345/candidates?page=1&perPage=20&resumeScoreMin=70&excludeRejected=true&orderColumn=createdAt&orderBy=DESC" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json"

Example Response

{
  "status": "success",
  "data": {
    "candidates": [
      {
        "jobCandidateId": 123,
        "jobId": 12345,
        "stageId": 5,
        "status": "PENDING",
        "createdAt": "2024-01-20T10:00:00Z",
        "updatedAt": "2024-01-21T14:30:00Z",
        "profileMatchScore": 85,
        "criteriaMatches": {
          "skills": 90,
          "experience": 80,
          "education": 75
        },
        "recommendToRecruitingFirm": true,
        "aiSummary": "Strong candidate with relevant experience in React and Node.js...",
        "candidate_details": {
          "id": 456,
          "firstName": "John",
          "lastName": "Doe",
          "email": "john.doe@example.com",
          "phone": "+1234567890",
          "currentJobTitle": "Senior 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"
        },
        "customFields": {
          "13": {
            "label": "Preferred Communication Channel",
            "value": "Email",
            "parentSection": "Personal Details"
          }
        }
      }
    ],
    "pagination": {
      "page": 1,
      "perPage": 20,
      "totalCandidates": 45,
      "totalPages": 3
    }
  }
}

Response Fields

FieldTypeDescription
statusstringResponse status (“success”)
data.candidatesarrayArray of job candidate objects
data.paginationobjectPagination information

Candidate Object Fields

FieldTypeDescription
jobCandidateIdnumberUnique identifier for this job candidate relationship
jobIdnumberThe job ID this candidate is associated with
stageIdnumberCurrent pipeline stage ID
statusstringCandidate status (e.g., “PENDING”, “APPROVED”, “REJECTED”)
createdAtstring (ISO 8601)When the candidate was added to the job
updatedAtstring (ISO 8601)Last update timestamp
profileMatchScorenumberAI-generated profile match score (0-100)
criteriaMatchesobjectBreakdown of criteria match scores
recommendToRecruitingFirmbooleanWhether candidate is recommended
aiSummarystringAI-generated summary of the candidate
candidate_detailsobjectFull candidate details (see candidate object structure)
customFieldsobjectCustom field values for the candidate, formatted as { customFieldId: { label, value, parentSection } }. Only included if custom field values exist.

Filtering Examples

Get candidates with high match scores:
GET /job-candidates/job/12345/candidates?resumeScoreMin=80
Get candidates in a specific pipeline stage:
GET /job-candidates/job/12345/candidates?stageId=5
Get candidates with score between 70 and 90:
GET /job-candidates/job/12345/candidates?resumeScoreMin=70&resumeScoreMax=90
Get active candidates (exclude rejected):
GET /job-candidates/job/12345/candidates?excludeRejected=true
Sort by candidate first name:
GET /job-candidates/job/12345/candidates?orderColumn=firstName&orderBy=ASC

Error Responses

Job not found:
{
  "error": {
    "code": "JOB_NOT_FOUND",
    "type": "resource_error",
    "message": "Job not found"
  }
}
Permission denied:
{
  "error": {
    "code": "PERMISSION_DENIED",
    "type": "authorization_error",
    "message": "You are not authorized to access this job"
  }
}
Invalid perPage value:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "perPage must be one of: 10, 20, 40, 80, 100"
  }
}

Get Candidates by Stage Type

Retrieve all candidates in pipeline stages matching a specific stage type with pagination, filtering by job ID and date range. This endpoint finds all stages of the given type in your company’s pipelines and returns candidates from those stages.

GET /job-candidates/stage

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Query Parameters

ParameterTypeRequiredDescription
typestringYesStage type to filter by. Must be one of the valid stage types (see Valid Stage Types below). Case-insensitive, will be converted to uppercase.
jobIdintegerNoFilter candidates by job ID
hiredAtstringNoFilter by hire date (ISO 8601). With time = that exact second; date-only = that full day.
hiredAtGtestringNoReturn records where hiredAt ≥ this datetime (ISO 8601).
startDatestringNoFilter by date range start (ISO 8601). When used with endDate, filters by hire date (start/end of day).
endDatestringNoFilter by date range end (ISO 8601). Use with startDate for a hire-date range.
pageintegerNoPage number (default: 1)
perPageintegerNoItems per page (1-100, default: 20). Maximum 100 allowed
orderColumnstringNoColumn to sort by. Valid values: createdAt, firstName. Default: createdAt
orderBystringNoSort order. Valid values: ASC, DESC. Default: DESC

Example Request

curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage?type=APPLIED&jobId=12345&page=1&perPage=20&startDate=2024-01-01T00:00:00Z&endDate=2024-12-31T23:59:59Z" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

Example Response

Each candidate in the response has candidate_details (the candidate’s profile), jobCandidateDetails (application data for the job), and onboardingFormDetails (onboarding form submissions, each with the jobId the flow is attached to).
{
  "status": "success",
  "data": {
    "candidates": [
      {
        "candidate_details": {
          "id": 12345,
          "firstName": "Sarah",
          "lastName": "Chen",
          "email": "sarah.chen@example.com",
          "phone": "+1-555-0123",
          "resume": "https://storage.example.com/resumes/sarah-chen.pdf",
          "currentJobTitle": "Senior Software Engineer",
          "currentCompany": "Tech Innovations Inc.",
          "city": "San Francisco",
          "country": "United States",
          "skills": ["JavaScript", "React", "Node.js", "TypeScript", "AWS"],
          "coverLetter": "I am excited to apply for this position...",
          "linkedin": "https://linkedin.com/in/sarahchen",
          "gender": "Female",
          "dateOfBirth": "1990-05-15",
          "nationality": "American",
          "industry": "Technology",
          "category": "Software Development",
          "companyId": "companyId_1",
          "createdAt": "2024-01-15T10:30:00.000Z",
          "updatedAt": "2024-01-20T14:45:00.000Z",
          "majors": ["Computer Science"],
          "summary": "Experienced software engineer with 8+ years in full-stack development, specializing in React and Node.js applications.",
          "languages": ["English", "Mandarin"],
          "educations": [
            {
              "degree": "Bachelor's",
              "field": "Computer Science",
              "institution": "Stanford University"
            }
          ],
          "githubUrl": "https://github.com/sarahchen",
          "certifications": [],
          "workExperiences": [
            {
              "title": "Senior Software Engineer",
              "company": "Tech Innovations Inc.",
              "duration": "3+ years"
            }
          ],
          "projectExperiences": []
        },
        "jobCandidateDetails": {
          "id": 45678,
          "jobId": 12345,
          "candidateId": 12345,
          "stageId": 789,
          "companyId": "companyId_1",
          "referralDetailsId": null,
          "status": "IN_PROGRESS",
          "evaluationStatus": "PENDING",
          "profileMatchScore": 92,
          "criteriaMatches": {
            "skills": 95,
            "experience": 90,
            "education": 88
          },
          "recommendToRecruitingFirm": true,
          "aiSummary": "Excellent candidate with strong technical skills matching all must-have requirements. 8+ years of relevant experience with React and Node.js. Strong educational background from top-tier university.",
          "noticePeriod": "2 weeks",
          "isWillingToRelocate": true,
          "expectedCTC": 150000,
          "currencyExpectedCTC": "USD",
          "expectedCTCPeriod": "ANNUALLY",
          "currentCTC": 130000,
          "currencyCurrentCTC": "USD",
          "currentCTCPeriod": "ANNUALLY",
          "screeningQuestionAnswer": [
            {
              "question": "Why are you interested in this role?",
              "answer": "I'm looking for opportunities to work on larger scale systems..."
            }
          ],
          "rejectedByClientId": null,
          "rejectedAt": null,
          "hiredByClientId": null,
          "hiredAt": null,
          "disqualificationReasons": null,
          "createdAt": "2024-01-15T10:30:00.000Z",
          "updatedAt": "2024-01-20T14:45:00.000Z"
        },
        "onboardingFormDetails": [
          {
            "id": 98,
            "status": "FORM_SUBMITTED",
            "createdAt": "2024-01-15T10:35:00.000Z",
            "updatedAt": "2024-01-15T11:20:00.000Z",
            "onboardingFlowId": 73,
            "jobId": 12345,
            "responses": [
              {
                "question": "Preferred start date",
                "answer": "2024-02-01"
              },
              {
                "question": "Work authorization status",
                "answer": "Authorized to work in the US"
              }
            ]
          }
        ],
        "customFields": {
          "13": {
            "label": "Preferred Communication Channel",
            "value": "Email",
            "parentSection": "Personal Details"
          }
        }
      }
    ],
    "pagination": {
      "page": 1,
      "perPage": 20,
      "totalCandidates": 45,
      "totalPages": 3
    }
  }
}

Response Fields

FieldTypeDescription
candidatesarrayArray of candidate objects. Each object has candidate_details, jobCandidateDetails, onboardingFormDetails, and optionally customFields.
candidates[].candidate_detailsobjectThe candidate’s profile (see Candidate Object Fields below).
candidates[].jobCandidateDetailsobjectAll fields related to this candidate’s application to the job: pipeline stage, status, AI match scores, CTC, hiring dates, etc. (see Job Candidate Details below).
candidates[].onboardingFormDetailsarrayOnboarding form submissions for this candidate (each includes jobId for the job the flow is attached to). See Onboarding Form Details below.
candidates[].customFieldsobjectCustom field values for the candidate, formatted as { customFieldId: { label, value, parentSection } }. Only included when custom field values exist.
pagination.pageintegerCurrent page number
pagination.perPageintegerItems per page
pagination.totalCandidatesintegerTotal number of candidates matching the filters
pagination.totalPagesintegerTotal number of pages

Candidate Object Fields

The candidate_details object contains the candidate’s profile (from the candidate_details table):
FieldTypeDescription
idintegerCandidate ID
firstNamestringFirst name
lastNamestringLast name
emailstringEmail address
phonestringPhone number
resumestringResume URL
currentJobTitlestringCurrent job title
currentCompanystringCurrent company
citystringCity
countrystringCountry
skillsstring/arraySkills (comma-separated or array)
coverLetterstringCover letter text
linkedinstringLinkedIn profile URL
genderstringGender
dateOfBirthstringDate of birth
nationalitystringNationality
industrystringIndustry
categorystringCategory
majorsstringMajors/fields of study
summarystringProfessional summary
languagesarrayArray of languages
educationsarrayArray of education objects
githubUrlstringGitHub profile URL
certificationsarrayArray of certification objects
workExperiencesarrayArray of work experience objects
projectExperiencesarrayArray of project experience objects

Job Candidate Details

The jobCandidateDetails object contains everything specific to the candidate’s application to the job:
FieldTypeDescription
idintegerJob candidate relationship ID
jobIdintegerJob ID
candidateIdintegerCandidate ID
stageIdintegerCurrent pipeline stage ID
companyIdstringCompany ID
statusstringApplication status (e.g., “IN_PROGRESS”, “REJECTED”)
evaluationStatusstringEvaluation status (e.g., “PENDING”, “COMPLETED”)
profileMatchScorenumberAI-generated profile match score (0-100)
criteriaMatchesobjectDetailed matching scores by criteria category
recommendToRecruitingFirmbooleanWhether candidate is recommended for recruiting firm
aiSummarystringAI-generated summary of candidate match
noticePeriodstringNotice period
isWillingToRelocatebooleanWillingness to relocate
expectedCTCnumberExpected CTC
currencyExpectedCTCstringCurrency for expected CTC (e.g., “USD”)
expectedCTCPeriodstringPeriod for expected CTC (e.g., “ANNUALLY”)
currentCTCnumberCurrent CTC
currencyCurrentCTCstringCurrency for current CTC
currentCTCPeriodstringPeriod for current CTC
screeningQuestionAnswerarrayScreening question answers
rejectedByClientIdstringClient user ID who rejected (if rejected)
rejectedAtstringWhen rejected (ISO 8601)
hiredByClientIdstringClient user ID who hired (if hired)
hiredAtstringWhen hired (ISO 8601)
disqualificationReasonsobjectDisqualification reasons if any
referralDetailsIdintegerReferral details ID if referred
createdAtstringWhen the job candidate record was created (ISO 8601)
updatedAtstringLast update timestamp (ISO 8601)

Onboarding Form Details

Each item in onboardingFormDetails (at the candidate level) represents one onboarding form submission:
FieldTypeDescription
idintegerSubmission ID
statusstringSubmission status: NEW, FORM_REQUESTED, FORM_SUBMITTED
createdAtstringWhen the submission was created (ISO 8601)
updatedAtstringWhen the submission was last updated (ISO 8601)
onboardingFlowIdintegerID of the onboarding flow this submission belongs to
jobIdintegerJob ID the onboarding flow is attached to
responsesarrayQuestion/answer pairs from the form. Each item has question (string) and answer (string). Empty array if form not yet submitted.

Filtering Examples

Get all candidates in “APPLIED” stages:
curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage?type=APPLIED" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
Get candidates in “SCREENING” stages for a specific job:
curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage?type=SCREENING&jobId=12345" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
Get candidates in “INTERVIEW” stages added in a date range:
curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage?type=INTERVIEW&startDate=2024-01-01T00:00:00Z&endDate=2024-01-31T23:59:59Z" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
Get candidates in “HIRED” stages with pagination:
curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage?type=HIRED&page=2&perPage=50" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

Error Responses

Missing stage type:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Stage type is required"
  }
}
No stages found for type: When no stages match the specified type, the API returns an empty candidates array:
{
  "status": "success",
  "data": {
    "candidates": [],
    "pagination": {
      "page": 1,
      "perPage": 20,
      "totalCandidates": 0,
      "totalPages": 0
    }
  }
}
Invalid perPage:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "perPage must be between 1 and 100"
  }
}

Valid Stage Types

The following stage types are valid for filtering candidates:
Stage TypeDescriptionDefaultEditableDeletable
SOURCEDCandidates who have been sourced but haven’t appliedYesNo (name only)No
APPLIEDCandidates who have applied to the jobYesNo (name only)No
ASSESSMENTCandidates in assessment/interview stageYesYesYes
SCREENCandidates in screening stageYesYesYes
SHORTLISTEDCandidates who have been shortlistedYesYesYes
OFFERCandidates who have received an offerNoYesYes
ONBOARDINGCandidates in onboarding processNoYesYes
HIREDCandidates who have been hiredYesNo (name only)No
Notes:
  • Stage types are case-insensitive and will be converted to uppercase automatically

Notes

  • Stage Type Matching: The endpoint finds all pipeline stages in your company that match the specified type (case-insensitive). Candidates from all matching stages are returned.
  • Multiple Stages: If you have multiple pipelines with stages of the same type, candidates from all those stages will be included in the results.
  • Date Filtering: The startDate and endDate filters apply to the candidate’s creation date (createdAt field in job_candidate_details). If hiredAt is provided, it takes precedence over startDate.
  • Maximum perPage: The maximum number of candidates returned per request is 100.
  • Response Structure: Each candidate has candidate_details (profile), jobCandidateDetails (application data), and onboardingFormDetails (onboarding form submissions with jobId per item).
  • Stage Ownership: Only stages from pipelines in your company are considered.

Get Candidates by Stage ID

Retrieve all candidates in a specific pipeline stage with pagination, filtering by job ID and date range. This endpoint returns complete candidate details from both the candidate_details and job_candidate_details tables.

GET /job-candidates/stage/:stageId/candidates

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Path Parameters

ParameterTypeRequiredDescription
stageIdintegerYesThe unique identifier of the pipeline stage

Query Parameters

ParameterTypeRequiredDescription
jobIdintegerNoFilter candidates by job ID
startDatestringNoFilter by date range start (ISO 8601 format, e.g., “2024-01-01T00:00:00Z”). Filters by candidate creation date
endDatestringNoFilter by date range end (ISO 8601 format, e.g., “2024-12-31T23:59:59Z”). Filters by candidate creation date
pageintegerNoPage number (default: 1)
perPageintegerNoItems per page (1-100, default: 20). Maximum 100 allowed
orderColumnstringNoColumn to sort by. Valid values: createdAt, firstName. Default: createdAt
orderBystringNoSort order. Valid values: ASC, DESC. Default: DESC

Example Request

curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage/789/candidates?jobId=12345&page=1&perPage=20&startDate=2024-01-01T00:00:00Z&endDate=2024-12-31T23:59:59Z" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

Example Response

The response structure is identical to Get Candidates by Stage Type, with candidates from the specific stage:
{
  "status": "success",
  "data": {
    "candidates": [
      {
        "candidate_details": {
          "id": 12345,
          "firstName": "Sarah",
          "lastName": "Chen",
          "email": "sarah.chen@example.com"
        },
        "jobCandidateDetails": {
          "id": 45678,
          "jobId": 12345,
          "stageId": 789,
          "profileMatchScore": 92
        },
        "onboardingFormDetails": [],
        "customFields": {}
      }
    ],
    "pagination": {
      "page": 1,
      "perPage": 20,
      "totalCandidates": 1,
      "totalPages": 1
    }
  }
}

Response Fields

The response structure matches Get Candidates by Stage Type. See that section for detailed field descriptions.

Filtering Examples

Get candidates in a stage for a specific job:
curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage/789/candidates?jobId=12345" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
Get candidates added in a date range:
curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage/789/candidates?startDate=2024-01-01T00:00:00Z&endDate=2024-01-31T23:59:59Z" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
Get candidates with pagination:
curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage/789/candidates?page=2&perPage=50" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"
Get candidates sorted by first name:
curl -X GET "https://partner-api.taptalent.io/v1/partner/job-candidates/stage/789/candidates?orderColumn=firstName&orderBy=ASC" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

Error Responses

Missing stage ID:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Stage ID is required"
  }
}
Stage not found:
{
  "error": {
    "code": "STAGE_NOT_FOUND",
    "type": "resource_error",
    "message": "Stage not found"
  }
}
Unauthorized access:
{
  "error": {
    "code": "PERMISSION_DENIED",
    "type": "authorization_error",
    "message": "You are not authorized to access this stage"
  }
}
Invalid perPage:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "perPage must be between 1 and 100"
  }
}
Job not found (when jobId filter is provided):
{
  "error": {
    "code": "JOB_NOT_FOUND",
    "type": "resource_error",
    "message": "Job not found"
  }
}

Custom Fields in Response

The response includes a customFields object when custom field values exist for the candidate. The format is:
{
  "customFields": {
    "13": {
      "label": "Preferred Communication Channel",
      "value": "Email",
      "parentSection": "Personal Details"
    }
  }
}
Where:
  • The key is the customFieldId (as a string)
  • Each value object contains:
    • label: The display name of the custom field
    • 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

Notes

  • Maximum perPage: The maximum number of candidates returned per request is 100
  • Date Range Filtering: The startDate and endDate filters apply to the candidate’s creation date (createdAt field in job_candidate_details)
  • Response structure: Each candidate has candidate_details (profile), jobCandidateDetails (application data: stage, status, AI scores, CTC, hiring dates, etc.), and onboardingFormDetails (onboarding form submissions with jobId per item)
  • Stage Ownership: You can only access candidates in stages that belong to pipelines in your company
  • Job Filtering: When jobId is provided, only candidates associated with that specific job are returned
  • Custom Fields Format: Custom fields are fetched from the normalized customFieldValues table and include field labels and parent sections for better usability

Update Job Candidate

Update application-specific fields for a job candidate (e.g. evaluation status, notice period, CTC). Use a partial body: send only the fields you want to change. To move the candidate to another stage, use Move Candidate to Stage instead.

PATCH /job-candidates/:jobCandidateId

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Path Parameters

ParameterTypeRequiredDescription
jobCandidateIdintegerYesThe unique identifier of the job candidate

Request Body (all optional; at least one required)

FieldTypeDescription
noticePeriodstringNotice period (e.g. “2 weeks”, “1 month”). Pass empty string to clear.
expectedCTCnumberExpected CTC amount
currencyExpectedCTCstringCurrency code (e.g. “USD”)
expectedCTCPeriodstringPeriod (e.g. “ANNUALLY”). Default: “ANNUALLY”
currentCTCnumberCurrent CTC amount
currencyCurrentCTCstringCurrency code
currentCTCPeriodstringPeriod. Default: “ANNUALLY”
isWillingToRelocatebooleanWhether the candidate is willing to relocate

Example Request

curl -X PATCH "https://partner-api.taptalent.io/v1/partner/job-candidates/12345" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "noticePeriod": "2 weeks",
    "expectedCTC": 120000,
    "currencyExpectedCTC": "USD",
    "expectedCTCPeriod": "ANNUALLY",
    "isWillingToRelocate": true
  }'

Example Response

{
  "status": "success",
  "message": "Job candidate updated successfully",
  "data": {
    "id": 12345,
    "jobId": 7373,
    "candidateId": 77774040,
    "stageId": 4043,
    "companyId": "63a9df22-5c41-49bc-878b-996e83477e57",
    "status": "IN_PROGRESS",
    "noticePeriod": "2 weeks",
    "expectedCTC": 120000,
    "currencyExpectedCTC": "USD",
    "expectedCTCPeriod": "ANNUALLY",
    "currentCTC": 0,
    "currencyCurrentCTC": "USD",
    "currentCTCPeriod": "ANNUALLY",
    "isWillingToRelocate": true,
    "updatedAt": "2026-02-02T18:00:00.000Z"
  }
}

Error Responses

Invalid jobCandidateId:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Invalid jobCandidateId"
  }
}
Job candidate not found:
{
  "error": {
    "code": "JOB_CANDIDATE_NOT_FOUND",
    "type": "resource_error",
    "message": "Job candidate not found"
  }
}
No fields to update:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "At least one updatable field is required"
  }
}

Delete Job Candidate

Remove a candidate from a job. This deletes the job-candidate relationship; the candidate profile remains in your company and can still be associated with other jobs.

DELETE /job-candidates/:jobCandidateId

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Path Parameters

ParameterTypeRequiredDescription
jobCandidateIdintegerYesThe unique identifier of the job candidate to remove

Example Request

curl -X DELETE "https://partner-api.taptalent.io/v1/partner/job-candidates/12345" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv"

Example Response

{
  "status": "success",
  "message": "Job candidate removed successfully"
}

Webhook

A candidate.removed_from_job webhook event is sent when a job candidate is deleted:
{
  "event": "candidate.removed_from_job",
  "timestamp": "2026-02-02T18:00:00Z",
  "companyId": "your-company-id",
  "data": {
    "jobId": 7373,
    "jobCandidateIds": [12345],
    "candidateIds": [77774040]
  }
}

Error Responses

Invalid jobCandidateId:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Invalid jobCandidateId"
  }
}
Job candidate not found:
{
  "error": {
    "code": "JOB_CANDIDATE_NOT_FOUND",
    "type": "resource_error",
    "message": "Job candidate not found"
  }
}

Notes

  • Only the job-candidate link is deleted; the candidate record in your company is not deleted.
  • The candidate can still appear in other jobs they are associated with.

Move Candidate to Stage

Move a candidate to a different pipeline stage within a job. This updates the candidate’s current stage in the hiring pipeline.

PUT /job-candidates/:jobCandidateId/stage

Authentication

Requires API key authentication via Authorization: Bearer YOUR_API_KEY header.

Path Parameters

ParameterTypeRequiredDescription
jobCandidateIdintegerYesThe unique identifier of the job candidate

Request Body

FieldTypeRequiredDescription
stageIdintegerYesThe ID of the pipeline stage to move the candidate to

Request Body Example

{
  "stageId": 789
}

Example Request

curl -X PUT "https://partner-api.taptalent.io/v1/partner/job-candidates/12345/stage" \
  -H "Authorization: Bearer sk_live_AbCdEfGhIjKlMnOpQrStUv" \
  -H "Content-Type: application/json" \
  -d '{
    "stageId": 789
  }'

Example Response

{
  "status": "success",
  "message": "Candidate moved to stage successfully",
  "data": {
    "id": 12345,
    "jobId": 12345,
    "candidateId": 456,
    "stageId": 789,
    "status": "IN_PROGRESS"
  }
}

Response Fields

FieldTypeDescription
statusstringResponse status (“success”)
messagestringSuccess message
data.idintegerJob candidate ID
data.jobIdintegerJob ID
data.candidateIdintegerCandidate ID
data.stageIdintegerNew pipeline stage ID
data.statusstringCandidate status (typically “IN_PROGRESS”)

Error Responses

Missing stageId:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "stageId is required"
  }
}
Invalid jobCandidateId:
{
  "error": {
    "code": "INVALID_REQUEST",
    "type": "validation_error",
    "message": "Invalid jobCandidateId"
  }
}
Job candidate not found:
{
  "error": {
    "code": "JOB_CANDIDATE_NOT_FOUND",
    "type": "resource_error",
    "message": "Job candidate not found"
  }
}
Stage not found:
{
  "error": {
    "code": "STAGE_NOT_FOUND",
    "type": "resource_error",
    "message": "Stage not found"
  }
}
Unauthorized access to stage:
{
  "error": {
    "code": "PERMISSION_DENIED",
    "type": "authorization_error",
    "message": "You are not authorized to access this stage"
  }
}

Notes

  • The candidate’s status will be automatically set to “IN_PROGRESS” when moved to a new stage
  • You can only move candidates to stages that belong to pipelines in your company

Use Cases

Fetching Job Candidates

Retrieve job candidates with their AI matching scores and evaluation status:
  • Display candidates for a specific job ranked by match score
  • Filter candidates by match score (e.g., show only candidates with 70+ match)
  • Review how well candidates meet your job criteria
  • Track evaluation status and hiring progress
  • Access AI-generated summaries explaining candidate fit
  • Filter by pipeline stage to see candidates at different hiring stages
  • Exclude rejected candidates to focus on active prospects

Uploading Resumes to Jobs

Upload resumes directly to jobs for parsing and candidate creation:
  • Associate resumes with specific job postings
  • Automatically create job candidates with AI evaluation
  • Receive AI matching scores based on job criteria
  • See which candidates best match your “Must Have” requirements
  • Track candidate progress through the hiring pipeline
Important for Recruiters: The quality of your criterionDetails directly impacts the accuracy of candidate matching. Well-defined, specific criteria will result in more accurate match scores and better candidate recommendations. Vague or generic criteria may lead to less reliable matching results.

Next Steps