Skip to main content
TalentUnveiled sends an HTTP POST to your endpoint whenever a subscribed event occurs. Subscribe an endpoint to specific events and verify each delivery’s signature.

Manage endpoints

You can manage webhook endpoints from Developer Settings → Webhooks in the HR portal, or programmatically via the v2 API: Subscriptions. Set event_types to the list of events you want. An empty list means all events. Set enabled: false to pause an endpoint without deleting it. Handle event types you don’t recognize gracefully — log them and still return 2xx; the set can grow over time, and all-events subscribers also receive legacy events such as interview_v2.completed (described under Events).
A URL can be registered once per organization. POST /api/v2/webhooks (and PATCH /api/v2/webhooks/{id} when you change url) returns 409 with code already_exists if that URL is already one of your own webhooks — distinct from the idempotency 409 (idempotency_key_conflict). Different organizations may register the same URL.

Payload envelope

Every webhook delivery has this envelope structure:
Deliveries are at-least-once and not ordered — make your handler idempotent (key on id) and order-independent. The event reference below describes each event’s payload contents; on the wire they always arrive inside the envelope above, so read body.payload.… (the interview.completed example is shown fully wrapped).

Verifying signatures

Each request includes signing headers. Verify the signature before trusting a payload:

Delivery & retries

Return 2xx quickly — verify the signature, enqueue, and process asynchronously. TalentUnveiled retries failed deliveries with exponential backoff:

Events

Every event whose payload has an application block carries external_id on it — the correlation id you set when creating the application (null when unset) — so any event (application.*, interview.completed, cv_evaluation.completed, insights.completed) can be routed back to your own record without storing the TalentUnveiled id.

application.created

Fired when a new application is created (any source — API, candidate portal, or ATS import). The payload contains the application (id, external_id, status, created_at), candidate, and job (id, title). external_id is the correlation id you set when creating the application (null when unset), so you can route the event to your own record without storing the TalentUnveiled id. Its absence past your expected SLA is the signal a create was lost upstream.

application.status_changed

Fired when an application’s pipeline status changes. The payload adds previous_status alongside the application, candidate, and job blocks. Each transition is a distinct event, so a candidate moving applied → screened → hired delivers three events.

interview.completed

Fired when a v3 interview finishes and scoring is ready. The payload carries enough to triage; fetch the full result (per-criterion scores, transcript) via GET /api/v2/applications/{id}/interview.
is_eligible: false means the candidate failed a required criterion — surface it to a recruiter, never auto-reject. overall_score is 0–5 (or null when not gradable), independent of eligibility.

cv_evaluation.completed

Fired when a CV evaluation finishes scoring. The payload carries the application and a cv_evaluation block (id, overall_score); fetch the per-criterion breakdown via GET /api/v2/applications/{id}/cv-evaluation.

insights.completed

Fired when the combined CV + interview insights finish. The payload carries the application and an insights block (overall_score, hiring_recommendation, is_eligible); fetch the full insights via GET /api/v2/applications/{id}/insights.

job_application.deleted

Fired when an application is removed. The payload is a snapshot of the application (id, status, created_at, candidate, job) captured immediately before deletion — the definitive “record is gone” signal.

interview_v2.completed

Fired when a legacy (previous-engine) interview finishes. Jobs created through API v2 use the v3 engine and emit interview.completed instead, so you only see interview_v2.completed for older jobs still on the previous interview engine — and only if you subscribe to all events (empty event_types). Treat it as a completion signal for those legacy interviews.