TapTalent sends webhook events for various operations. All webhook payloads follow a consistent structure.
Payload structure
Every webhook body looks like:
{
"event": "event.type.name",
"timestamp": "2024-01-20T14:45:00Z",
"companyId": 12345,
"data": {
// Event-specific data
}
}
| Field | Type | Description |
|---|
event | string | The event type (e.g. candidate.updated) |
timestamp | string | ISO 8601 UTC timestamp when the event occurred |
companyId | integer | The TapTalent company ID the event belongs to |
data | object | Event-specific payload (see each event below) |
All webhook requests include:
Content-Type: application/json
X-Webhook-Event: The event type (e.g. resume.bulk_upload_parse.started)
X-Webhook-Timestamp: ISO 8601 timestamp of when the event occurred
X-Webhook-Key: Your webhook verification secret. When you have generated a webhook key in the dashboard, TapTalent sends it in this header. Compare it to your stored key to verify the request came from TapTalent. If no key has been set, the header may be empty.
Resume events
resume.bulk_upload_parse.started
Triggered when a bulk resume upload batch starts processing.
{
"event": "resume.bulk_upload_parse.started",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"batchId": 12345,
"fileCount": 25,
"jobId": 12345
}
}
| Field | Type | Description |
|---|
batchId | integer | The batch ID for this upload |
fileCount | number | Total number of resumes in the batch |
jobId | integer or null | The job ID if resumes were uploaded to a specific job, otherwise null |
resume.bulk_upload_parse.completed
Triggered when a bulk resume upload batch completes processing.
{
"event": "resume.bulk_upload_parse.completed",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"batchId": 12345,
"status": "COMPLETED",
"fileCount": 25,
"successCount": 23,
"failedCount": 2,
"jobId": 12345
}
}
| Field | Type | Description |
|---|
batchId | integer | The batch ID for this upload |
status | string | Batch processing status (e.g. “COMPLETED”) |
fileCount | number | Total number of resumes in the batch |
successCount | number | Number of resumes successfully parsed |
failedCount | number | Number of resumes that failed to parse |
jobId | integer or null | The job ID if resumes were uploaded to a specific job, otherwise null |
resume.bulk_upload_parse.failed
Triggered when a bulk resume upload batch fails before processing begins (e.g. validation errors, invalid URLs).
{
"event": "resume.bulk_upload_parse.failed",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"error": "Error message describing the failure"
}
}
| Field | Type | Description |
|---|
error | string | Error message describing why the batch failed |
Job events (recruiter actions)
job.created
Triggered when a recruiter creates a new job from the dashboard.
{
"event": "job.created",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"title": "Software Engineer"
}
}
job.updated
Triggered when a recruiter updates a job’s basic details (e.g. title, description, location) from the dashboard. Does not fire when only the job status is changed.
{
"event": "job.updated",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"updatedFields": ["title", "description", "city"]
}
}
job.status_changed
Triggered when a recruiter changes a job’s status (e.g. Draft → Active, Active → Inactive/Closed).
{
"event": "job.status_changed",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"status": "INACTIVE",
"previousStatus": "ACTIVE",
"closingStatus": "Filled",
"closingReason": "Position filled internally"
}
}
| Field | Type | Description |
|---|
jobId | integer | The job ID |
status | string | New status (e.g. ACTIVE, INACTIVE, DRAFT) |
previousStatus | string or null | Status before the change |
closingStatus | string or null | If the job was closed, the selected closing reason (e.g. Filled, Cancelled) |
closingReason | string or null | Optional text or detail for the closing |
Candidate events (recruiter actions)
candidate.added_to_job
Triggered when a recruiter adds one or more candidates to a job (e.g. from company list, AI search, or moving from another job).
{
"event": "candidate.added_to_job",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"stageId": 2,
"candidateIds": ["candidateId-1", "candidateId-2"],
"jobCandidateIds": [101, 102],
"count": 2
}
}
| Field | Type | Description |
|---|
jobId | integer | The job the candidates were added to |
stageId | integer | The pipeline stage ID (optional in payload) |
candidateIds | array | Candidate IDs that were added |
jobCandidateIds | array | Job–candidate record IDs for each added candidate |
count | number | Number of candidates added |
candidate.stage_changed
Triggered when a recruiter moves one or more candidates to a different pipeline stage (e.g. kanban drag-and-drop).
{
"event": "candidate.stage_changed",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"currentStageId": 2,
"nextStageId": 3,
"jobCandidateIds": [101, 102],
"candidateIds": ["candidateId_1", "candidateId_2"]
}
}
candidate.hired
Triggered when a recruiter moves one or more candidates to the Hired stage.
{
"event": "candidate.hired",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"jobCandidateIds": [101, 102],
"candidateIds": ["candidateId_1", "candidateId_2"]
}
}
candidate.rejected
Triggered when a recruiter rejects or disqualifies one or more candidates, or when an automated screening flow disqualifies a candidate.
{
"event": "candidate.rejected",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"jobCandidateIds": [101],
"candidateIds": ["candidateId_1"],
"jobCandidateId": 101,
"candidateId": "candidateId_1",
"reason": "Automated screening flow rejected."
}
}
candidate.removed_from_job
Triggered when one or more candidates are removed from a job. This is sent when:
- A recruiter uses the bulk “Remove from job” / “Delete” action on candidates in that job (move-job-candidates with delete), or
- A recruiter deletes one or more candidates from the company (DELETE /candidates), in which case one event is sent per job those candidates were in.
{
"event": "candidate.removed_from_job",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"jobCandidateIds": [101, 102],
"candidateIds": ["candidateId_1", "candidateId_2"]
}
}
| Field | Type | Description |
|---|
jobId | integer | The job the candidates were removed from |
jobCandidateIds | array | Job–candidate record IDs that were removed |
candidateIds | array | Candidate IDs that were removed from the job |
candidate.updated
Triggered when a recruiter updates a candidate’s profile or job-application details from the dashboard.
- Profile (
scope: "profile"): Company-level profile (e.g. name, email, phone, resume, skills) via Update company candidate details or Update job candidate details (email/phone).
- Application (
scope: "application"): Application for a specific job (e.g. expected CTC, notice period, hired date) via Update job candidate application.
Profile update example:
{
"event": "candidate.updated",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"candidateId": "candidateId_1",
"updatedFields": ["firstName", "email", "phone"],
"scope": "profile"
}
}
Application update example (includes jobCandidateId and jobId):
{
"event": "candidate.updated",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobCandidateId": 101,
"jobId": 12345,
"candidateId": "candidateId_1",
"updatedFields": ["expectedCTC", "noticePeriod"],
"scope": "application"
}
}
Job candidate scoring events
job.candidate.score.completed
Triggered when AI scoring is completed for a candidate’s application to a job. This event is sent after the candidate’s resume has been analyzed and matched against the job requirements, and a score has been calculated.
{
"event": "job.candidate.score.completed",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"jobCandidateId": 101,
"candidateId": "candidateId_1",
"score": 85.5
}
}
| Field | Type | Description |
|---|
jobId | integer | The job ID the candidate applied to |
jobCandidateId | integer | The job–candidate record ID |
candidateId | string | The candidate ID |
score | number | The AI-generated match score (typically 0-100) representing how well the candidate matches the job requirements |
job.candidate.score.failed
Triggered when AI scoring fails for a candidate’s application to a job. This event is sent when the scoring process encounters an error (e.g. insufficient candidate data, processing error, or service unavailability).
{
"event": "job.candidate.score.failed",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"jobId": 12345,
"jobCandidateId": 101,
"candidateId": "candidateId_1",
"error": "Scoring failed: insufficient candidate data"
}
}
| Field | Type | Description |
|---|
jobId | integer | The job ID the candidate applied to |
jobCandidateId | integer | The job–candidate record ID |
candidateId | string | The candidate ID |
error | string | Error message describing why scoring failed |
Assessment events
assessment.ready
Triggered when questions have been generated for an assessment (e.g. after Auto-Generate Assessment or Generate Questions). You can then fetch the assessment or invite candidates.
{
"event": "assessment.ready",
"timestamp": "2024-01-20T14:45:00Z",
"data": {
"assessmentId": "assessmentId_1",
"message": "Assessment questions generated and ready",
"questionCount": 5
}
}
| Field | Type | Description |
|---|
assessmentId | string | The assessment ID |
message | string | Confirmation message |
questionCount | number | Number of questions added to the assessment |
interview.started
Triggered when a candidate has started an assessment interview (e.g. opened the interview and it has begun). Use this to track when invited candidates begin their assessment.
{
"event": "interview.started",
"timestamp": "2024-01-20T14:45:00Z",
"companyId": "company_id_12345",
"data": {
"assessmentId": "assessmentId_1",
"submissionId": "submissionId_1",
"interviewStatus": "STARTED",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"jobCandidateId": 101
}
}
| Field | Type | Description |
|---|
assessmentId | string | The assessment ID |
submissionId | string | The interview submission ID |
interviewStatus | string | Status of the interview (e.g. STARTED) |
firstName | string | Candidate’s first name (if available) |
lastName | string | Candidate’s last name (if available) |
email | string | Candidate’s email (if available) |
jobCandidateId | number or null | Job-candidate ID if the candidate was invited via a job (optional) |
interview.scoring_completed
Triggered when scoring has finished for an interview submission. Use this to sync results to your system or notify recruiters.
{
"event": "interview.scoring_completed",
"timestamp": "2024-01-20T15:00:00Z",
"companyId": 12345,
"data": {
"assessmentId": "assessmentId_1",
"submissionId": "submissionId_1",
"status": "COMPLETED",
"score": 78,
"bucket": "Good Fit",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"jobCandidateId": 101
}
}
| Field | Type | Description |
|---|
assessmentId | string | The assessment ID |
submissionId | string | The interview submission ID |
status | string | Status (e.g. COMPLETED) |
score | number | Overall score for the submission |
bucket | string or null | Evaluation bucket (e.g. “Strong Fit”, “Good Fit”) if configured |
firstName | string | Candidate’s first name (if available) |
lastName | string | Candidate’s last name (if available) |
email | string | Candidate’s email (if available) |
jobCandidateId | number or null | Job-candidate ID if linked to a job (optional) |
interview.ended
Triggered when a candidate has finished or left the interview (e.g. completed all questions, timed out, or ended the session). Use this to track completion and optionally wait for interview.scoring_completed for the final score.
{
"event": "interview.ended",
"timestamp": "2024-01-20T14:55:00Z",
"companyId": 12345,
"data": {
"assessmentId": "assessmentId_1",
"submissionId": "submissionId_1",
"status": "FINISHED",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"jobCandidateId": 101
}
}
| Field | Type | Description |
|---|
assessmentId | string | The assessment ID |
submissionId | string | The interview submission ID |
status | string | Status (e.g. FINISHED) |
firstName | string | Candidate’s first name (if available) |
lastName | string | Candidate’s last name (if available) |
email | string | Candidate’s email (if available) |
jobCandidateId | number or null | Job-candidate ID if linked to a job (optional) |
interview.error
Triggered when an error occurs during the interview flow (e.g. failed to start, scoring failure, or permission issues). Use this to monitor failures and alert or retry as needed.
{
"event": "interview.error",
"timestamp": "2024-01-20T14:46:00Z",
"companyId": 12345,
"data": {
"assessmentId": "assessmentId_1",
"submissionId": "submissionId_1",
"errorType": "START_FAILED",
"errorMessage": "Failed to start interview",
"timestamp": 1708363560000
}
}
| Field | Type | Description |
|---|
assessmentId | string | The assessment ID |
submissionId | string or null | The interview submission ID (if one was created) |
errorType | string | Error category (e.g. START_FAILED, SCORING_FAILED, AUDIO_PERMISSION_DENIED) |
errorMessage | string | Human-readable error message |
timestamp | number | Unix timestamp when the error occurred |
interview.complete_later
Triggered when a candidate clicks “Complete later (not recommended)” on the pre-interview setup screen. The candidate has chosen to save their link and finish the assessment later instead of starting now.
{
"event": "interview.complete_later",
"timestamp": "2024-01-20T14:50:00Z",
"companyId": 12345,
"data": {
"assessmentId": "assessmentId_1",
"firstName": "John",
"lastName": "Doe",
"email": "john.doe@example.com",
"jobCandidateId": 101,
"timestamp": 1708363800000
}
}
| Field | Type | Description |
|---|
assessmentId | string | The assessment ID |
firstName | string | Candidate’s first name (if available) |
lastName | string | Candidate’s last name (if available) |
email | string | Candidate’s email (if available) |
jobCandidateId | number or null | Job-candidate ID if linked to a job (optional) |
timestamp | number | Unix timestamp when the candidate chose complete later |
More event types may be added in future releases. Check this page for updates.