Candidate Processing Events
Candidate Processing Events
Candidate processing events tell you what happened to a candidate you submitted through the Candidates API.
Processing is always asynchronous. Creating or updating a candidate returns as soon as the record is written, and the heavy work — fetching and extracting the CV, enriching the profile, and indexing it for internal sourcing — is queued behind the candidate's priority band. These events are how you learn the outcome without polling.
Available Events
| Event | Description |
|---|---|
CANDIDATE_PROCESSING_STARTED | A candidate has started processing |
CANDIDATE_PROCESSING_COMPLETED | A candidate finished processing and is now searchable |
CANDIDATE_PROCESSING_FAILED | Candidate processing failed; errorReason explains why |
Every run sends CANDIDATE_PROCESSING_STARTED first, then exactly one of CANDIDATE_PROCESSING_COMPLETED or CANDIDATE_PROCESSING_FAILED.
CANDIDATE_PROCESSING_STARTED
Triggered when a queued candidate is picked up and work begins on it. The gap between your API call and this event is queue time, which depends on the priority you set and how much work is ahead of it.
Payload
{
"event": "CANDIDATE_PROCESSING_STARTED",
"eventId": "evt_abc123",
"eventTimestamp": "2024-01-15T10:30:00.000Z",
"data": {
"recordId": "candidate_xyz789",
"organizationId": "org_123456",
"externalId": "your_external_candidate_id"
}
}Data Fields
| Field | Type | Description |
|---|---|---|
recordId | string | Popp internal candidate profile ID |
organizationId | string | The organization the candidate was processed for |
externalId | string | Your external reference ID for the candidate, if you supplied one |
CANDIDATE_PROCESSING_COMPLETED
Triggered when the candidate has been extracted, enriched and indexed. From this point the candidate is searchable in internal sourcing.
Payload
{
"event": "CANDIDATE_PROCESSING_COMPLETED",
"eventId": "evt_abc123",
"eventTimestamp": "2024-01-15T10:30:00.000Z",
"data": {
"recordId": "candidate_xyz789",
"organizationId": "org_123456",
"externalId": "your_external_candidate_id"
}
}Data Fields
Same as CANDIDATE_PROCESSING_STARTED.
CANDIDATE_PROCESSING_FAILED
Triggered when the run ends without the candidate being indexed. The candidate record still exists with the fields you supplied; only the processing failed.
Payload
{
"event": "CANDIDATE_PROCESSING_FAILED",
"eventId": "evt_abc123",
"eventTimestamp": "2024-01-15T10:30:00.000Z",
"data": {
"recordId": "candidate_xyz789",
"organizationId": "org_123456",
"externalId": "your_external_candidate_id",
"errorReason": "CV text extraction failed"
}
}Data Fields
| Field | Type | Description |
|---|---|---|
errorReason | string | Why the run failed. See the table below. |
Plus the fields shared with the other two events.
Failure Reasons
errorReason | What it means | What to do |
|---|---|---|
CV text extraction failed | The document was fetched but could not be read — corrupt, password-protected, or an unsupported type | Check the file opens, and that it is a PDF, DOCX, DOC, HTML or plain text |
CV yielded no text | The document was read but contained no extractable text, e.g. a scan with no text layer | Re-submit a text-bearing version of the document |
No vector DB tenant configured for the organization | Internal sourcing is enabled for the organization but not finished being set up | Contact Popp support — this is a configuration issue, not a problem with your request |
Processing exhausted retries | The run failed repeatedly against a transient problem and gave up | Re-submit the candidate; if it recurs, contact Popp support |
Any other value is the underlying error from a downstream service, passed through as-is.
Re-processing
Updating a candidate queues it again, so a candidate that is updated several times produces several runs and therefore several STARTED / COMPLETED pairs. Treat these events as idempotent: key on recordId and act on the latest, rather than assuming one pair per candidate.
If an update arrives while an earlier run is still in flight, the earlier run is superseded and stops without sending a terminal event. You receive the terminal event for the newest run only.
Candidates with no sourcing organizationThese events are delivered to the organization the candidate is processed for. If a candidate belongs to no organization with internal sourcing enabled, there is no organization to notify and you will not receive events for it.
Related Documentation
- Webhook Event Structure - The shared payload envelope
- Webhook Authentication - Verifying the signature
- Managing Webhooks - Subscribing to these events
Updated about 12 hours ago
