Skip to main content

Overview

Webhooks allow you to receive real-time notifications when events occur in the Gather API. Configure webhooks to be notified when interviews are completed, statuses change, or audio generation finishes.

Webhook Events

The following events are available. Interview & question events
  • question.audio_generated - Question audio generation completed
  • interview.created - Interview created
  • interview.updated - Interview updated
Candidate interview events
  • candidate_interview.invited - Invite sent to a candidate
  • candidate_interview.partially_completed - Candidate answered some but not all questions
  • candidate_interview.completed - Candidate completed the interview
  • candidate_interview.status_changed - Candidate interview status changed
  • candidate_interview.expired - Candidate interview expired before completion
Workflow events
  • workflow.enrollment.created - Candidate enrolled in a job workflow
  • workflow.enrollment.completed - Candidate passed the final workflow step
  • workflow.enrollment.failed - Candidate failed a gated workflow step
  • workflow.step.invited - Invite sent for a workflow step
  • workflow.step.completed - Workflow step gate passed
  • workflow.step.failed - Workflow step gate failed
  • workflow.step.waiting_for_evaluation - Step awaiting asynchronous evaluation
Only the event names listed above are accepted when creating or updating a subscription. Subscribing (or updating) with an unknown event name is rejected with a 400; a request mixing valid and invalid names is rejected as a whole. Pre-existing configurations that contain legacy event names continue to read without error.

Webhook Delivery Format

Each webhook is delivered as an HTTP POST to your configured URL.

Request Headers

Request Body

The request body is a flat JSON object containing event-specific fields. The event type is not included in the body — read it from the X-Qualifi-Event header. Example for candidate_interview.completed:

Webhook Configuration

Webhooks can be configured per organization/team via the Gather API’s webhook configuration endpoints (/qsi/gather/webhooks — create, list, get, update, delete). Use the Webhook Delivery Logs endpoint to retrieve delivery history.
Deleting a configuration that has delivery history is rejected with a 400 to prevent accidental loss of that history. To delete the configuration and its deliveries, send DELETE /qsi/gather/webhooks/:id?deleteDeliveries=true.

Configuration Options

  • Multiple URLs: Supports multiple webhook URLs per organization
  • Event Filtering: Configure which events to receive
  • Retry Logic: Automatic retries with exponential backoff (3 attempts)
  • Signature Verification: HMAC-SHA256 signature for security

Webhook Delivery Logs

Retrieve a paginated history of webhook delivery attempts for the authenticated organization, sorted newest-first. Useful for debugging failed deliveries and reconciling expected vs. received events.
Webhook secrets are never returned in delivery logs.

Endpoint

GET /qsi/gather/webhook-deliveries

Query Parameters

string
Override team scope (must be allowed for the API key).
string
Filter to a single webhook configuration.
string
Filter by event type, e.g. candidate_interview.completed.
string
One of pending, processing, completed, failed.
string
Filter to deliveries whose payload contains this candidate interview ID. Useful for tracing the events emitted for a specific interview.
string
Inclusive lower bound on createdAt (ISO 8601).
string
Inclusive upper bound on createdAt (ISO 8601).
number
Page number, 1-indexed. Default 1.
number
Records per page, max 200. Default 50.

Response

Status State Machine

Webhook Signature Verification

Every delivery is signed two ways. New integrations should verify the recommended timestamped signature (X-Qualifi-Signature-V2); the legacy hex signature is kept only for backward compatibility. The X-Qualifi-Signature-V2 header has the form t=<timestamp>,v1=<hex>, where <hex> is the HMAC-SHA256 of the string "<timestamp>.<rawBody>" using your webhook secret, and <timestamp> is also sent in X-Qualifi-Timestamp. Because the timestamp is signed, this scheme lets you reject replayed deliveries.
  1. Parse t and v1 from the X-Qualifi-Signature-V2 header.
  2. Reject the delivery if t is outside your tolerance window (recommended: 5 minutes, i.e. |now − t| > 300s).
  3. Compute HMAC-SHA256(secret, "<t>.<rawBody>") and compare it to v1 in constant time.

Deprecated: hex signature (X-Qualifi-Signature)

The X-Qualifi-Signature header contains the HMAC-SHA256 hex digest of the raw JSON request body. It has no replay protection (the timestamp is not signed) and is deprecated — verify X-Qualifi-Signature-V2 instead. To verify it: compute HMAC-SHA256 of the raw body string with your secret and compare to the header.
Signature verification must use the exact raw JSON string from the request body. Re-serializing a parsed JSON object can change key order or whitespace and cause verification to fail.

Example Verification (timestamped)

Event Details

question.audio_generated

Triggered when question audio generation completes. Header: X-Qualifi-Event: question.audio_generated

candidate_interview.completed

Triggered when a candidate completes an interview. May fire when status changes to new_response or when the interview completion worker processes the interview. Header: X-Qualifi-Event: candidate_interview.completed

candidate_interview.status_changed

Triggered when candidate interview status changes. Header: X-Qualifi-Event: candidate_interview.status_changed

candidate_interview.invited

Triggered after an interview invite is actually sent to a candidate (not on mere record creation). For invites sent as part of a workflow step, workflow.step.invited fires instead, so the two never double-fire. Header: X-Qualifi-Event: candidate_interview.invited

candidate_interview.partially_completed

Triggered when a candidate has answered some, but not all, of an interview and the interview transitions from invited to partially completed. Header: X-Qualifi-Event: candidate_interview.partially_completed

candidate_interview.expired

Triggered when an invited or partially-completed candidate interview expires before completion. Header: X-Qualifi-Event: candidate_interview.expired

interview.created

Triggered when a new interview is created. Header: X-Qualifi-Event: interview.created

interview.updated

Triggered when an interview is updated. Header: X-Qualifi-Event: interview.updated

workflow.enrollment.created

Triggered when a candidate is enrolled in a job workflow. Organization/team scope is derived from the enrollment’s job. Header: X-Qualifi-Event: workflow.enrollment.created

workflow.enrollment.completed

Triggered when a candidate passes the final step of a workflow. Header: X-Qualifi-Event: workflow.enrollment.completed

workflow.enrollment.failed

Triggered when a candidate fails a gated workflow step; no further step invites are sent. Header: X-Qualifi-Event: workflow.enrollment.failed

workflow.step.invited

Triggered after an invite is sent for a workflow step. inviteUrl is the candidate-facing link with internal tokens removed; candidateInterviewId or candidateMeetingId is present depending on the step type. Header: X-Qualifi-Event: workflow.step.invited

workflow.step.completed

Triggered when a workflow step’s gate passes. hasNextStep indicates whether a subsequent step exists (a workflow.step.invited for the next step follows when it does). score/scoreThreshold are present when the step is scored. Header: X-Qualifi-Event: workflow.step.completed

workflow.step.failed

Triggered when a workflow step’s gate fails. Header: X-Qualifi-Event: workflow.step.failed

workflow.step.waiting_for_evaluation

Triggered when a step’s gate cannot be decided yet and is awaiting asynchronous evaluation (e.g. interview scoring). Header: X-Qualifi-Event: workflow.step.waiting_for_evaluation

Retry Logic

Webhooks use exponential backoff for failed deliveries:
  1. First attempt: Immediate
  2. Second attempt: After 1 minute
  3. Third attempt: After 5 minutes
If all retry attempts fail, the webhook delivery is marked as failed. Check your webhook endpoint availability and error handling.

Best Practices

  1. Verify Signatures: Always verify webhook signatures to ensure authenticity
  2. Idempotency: Handle duplicate webhook deliveries gracefully
  3. Quick Response: Respond to webhooks quickly (within 5 seconds)
  4. Error Handling: Return appropriate HTTP status codes
  5. Logging: Log all webhook events for debugging

Handling Webhooks

Step-by-step guide for handling webhooks

Candidate Interviews

Learn about candidate interview events