Skip to Content
ConceptsWebhooks Guide

Overview

Webhooks deliver real-time HTTP POST notifications to your server when events occur in Celper AI. Instead of polling the API for changes, you register a URL and the system pushes updates to you as they happen.

Each company can register up to 5 webhooks. Each webhook can subscribe to one or more event types and optionally filter by candidate status.

Events

EventDescription
analysis_readyInterview analysis completed for a candidate
candidate_status_changedA candidate’s status was updated
cv_analysis_completeCV scoring and AI evaluation finished
bulk_import_completeA bulk import job has finished processing

Delivery Format

When an event fires, the API sends an HTTP POST request to your webhook URL with a JSON body:

{ "event": "candidate_status_changed", "webhookId": "wh_abc123", "companyId": "comp_xyz", "timestamp": "2024-01-15T10:30:00Z", "data": { "candidateId": "cand_123", "jobPositionId": "pos_456", "status": "interviewed", "previousStatus": "invited" } }
FieldDescription
eventThe event type that triggered this delivery.
webhookIdThe ID of the webhook subscription that matched this event.
companyIdYour company ID.
timestampISO 8601 timestamp of when the event occurred.
dataEvent-specific payload. Structure varies by event type.

Signature Verification

Every webhook delivery is signed with HMAC-SHA256 so you can verify it came from Celper AI and was not tampered with in transit.

Each delivery includes two headers:

HeaderDescription
X-Celper-SignatureThe signature in the format sha256=<hex digest>.
X-Celper-TimestampUnix timestamp (seconds) of when the delivery was signed.

The signing input is {timestamp}.{raw request body} — the timestamp and body joined by a period. This ensures each delivery has a unique signature even when the payload is identical.

Replay protection: Reject any delivery whose timestamp is more than 5 minutes (300 seconds) from your server’s current time.

Always verify the signature before processing a webhook delivery.

# Signature verification is done server-side, not with curl.
# When testing with curl, you can inspect the headers:

curl -X POST https://your-server.com/webhooks/celper -H "Content-Type: application/json" -H "X-Celper-Signature: sha256=a1b2c3d4..." -H "X-Celper-Timestamp: 1712825400" -d '{"event":"candidate_status_changed","data":{...}}'

# To verify:
# 1. Build the signing input: "{timestamp}.{body}"
# 2. Compute HMAC-SHA256 using your webhook secret
# 3. Compare with the X-Celper-Signature header value
# 4. Reject if timestamp is more than 300 seconds from now

Retry Policy

If your endpoint does not respond with a 2xx status code within 5 seconds, the delivery is considered failed and will be retried.

AttemptDelay after failure
1st retry30 seconds
2nd retry2 minutes
3rd retry10 minutes
4th retry30 minutes
5th retry2 hours

After 5 failed delivery attempts, the delivery status is set to "exhausted" and no further retries are made for that specific event.

If a webhook accumulates 10 consecutive failed deliveries (across any events), it is automatically disabled. You can re-enable it from the API Management dashboard or via the API after fixing the issue.

Status Filters

When creating or updating a webhook, you can specify an optional statusFilters array to only receive candidate_status_changed events for specific statuses.

Valid status values:

new | invited | interviewed | selected | rejected | expired | failed | unevaluable

For example, setting statusFilters: ["selected", "rejected"] means you will only receive candidate_status_changed events when a candidate moves to the selected or rejected status. All other status transitions are silently skipped.

If statusFilters is omitted or empty, you receive events for all status changes.

Best Practices

  • Respond quickly — Return a 200 response within 5 seconds. Offload processing to a background queue or worker.
  • Always verify signatures — Check the X-Celper-Signature header using HMAC-SHA256 before processing any event. This prevents spoofed deliveries.
  • Handle duplicates idempotently — Due to retries, your endpoint may receive the same event more than once. Use the webhookId and timestamp to deduplicate.
  • Monitor delivery health — Use the GET /v1/webhooks/{id}/deliveries endpoint to check for failed deliveries and diagnose issues.
  • Test before going live — Use the POST /v1/webhooks/{id}/test endpoint to send a test event to your URL and verify your integration end-to-end.