Skip to content
DoverDoverDover Docs
Menu

Webhooks

Get a signed HTTPS request at your own endpoint each time a candidate applies, and verify it, test it, and handle retries.

Webhooks send an HTTPS request from Dover to a URL you choose when something happens. Today there is one event, Candidate applied, which fires each time someone applies to one of your jobs. Use it to update your own systems, post to a chat tool, or start a workflow, without checking Dover for new applicants. Adding and managing endpoints needs the Integrations company permission.


  1. Click Settings → Integrations.
  2. Open Webhooks.
  3. Under Add new endpoint, enter your Endpoint URL. It must be public and use HTTPS.
  4. Choose the Event, Candidate applied.
  5. Click Add endpoint.
  6. In Save your signing secret, click Copy signing secret and store it somewhere safe.

Active endpoints lists each endpoint with its Event and Status.

  • Pause or resume: use the switch to set an endpoint Active or Paused. A paused endpoint gets nothing, and requests waiting to be sent to it are cancelled.
  • Test: click Test to send a sample event to an active endpoint. Dover shows Test event queued.
  • Delete: click the delete icon and confirm.

Each request is a POST with a JSON body. The event type is candidate.application.created.

{
"id": "6f1f6c2e-...",
"type": "candidate.application.created",
"api_version": "2026-07-23",
"created_at": "2026-11-02T15:04:05+00:00",
"data": {
"client": { "id": "..." },
"job": { "id": "...", "title": "Senior Software Engineer" },
"application": {
"id": "...",
"applied_at": "2026-11-02T15:03:58+00:00",
"external_application_id": null,
"source": { "id": "...", "label": "Dover careers page" },
"candidate": {
"first_name": "Alice",
"last_name": "Johnson",
"full_name": "Alice Johnson",
"email": "[email protected]",
"linkedin_public_id": null
},
"application_questions": [{ "question": "Why this role?", "answer": "..." }]
}
}
}

A test event has the type webhook.test and only the company’s ID in data.

Every request has these headers:

Header What it holds
Dover-Webhook-Id The event’s ID. The same event has the same ID on every retry.
Dover-Webhook-Delivery-Id The ID of this delivery.
Dover-Webhook-Timestamp When Dover signed the request, in Unix seconds.
Dover-Webhook-Version The payload version, such as 2026-07-23.
Dover-Webhook-Signature The signature, as v1= followed by a hex value.
Idempotency-Key The event’s ID, so you can ignore repeats.

Check the signature before you trust a request.

  1. Read the raw request body, exactly as received.
  2. Join the Dover-Webhook-Timestamp value, a period, and the raw body.
  3. Compute an HMAC-SHA256 of that text, using your signing secret as the key, and write it as hex.
  4. Compare it to the value after v1= in Dover-Webhook-Signature, using a constant-time comparison.
import hashlib, hmac
def is_valid(secret: str, timestamp: str, body: bytes, header: str) -> bool:
signed = timestamp.encode() + b"." + body
expected = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
return hmac.compare_digest(f"v1={expected}", header)

Reject requests with an old timestamp to block replays. Use Dover-Webhook-Id to ignore an event you already handled.


Respond with a 2xx status within 10 seconds. If Dover gets a timeout, a network error, a 408, 425, 429, or any 5xx, it tries again about 5 minutes later, up to 10 attempts in total. Other responses, such as 400 or 404, aren’t retried. Dover doesn’t follow redirects.


Dover accepts only public HTTPS addresses. It rejects localhost, private network addresses, URLs with a username or password, and hosts it can’t resolve.

Delete the endpoint and add it again. The new endpoint gets a new secret, shown once.

Dover retries when it doesn’t get a 2xx answer in time. Use Dover-Webhook-Id or Idempotency-Key to ignore an event you already handled.

You can only test an Active endpoint. Switch it on first.

Only Candidate applied for now.