Events

Webhooks

API v115 August 2026·3 min read

Webhook configuration, payload, signature verification, timeout, and the two independent retry mechanisms behind asynchronous document generation.

A document request never returns the finished document inline. Doclift delivers it later as a webhook, once every generation in the request has finished.


Configuration

There is no API endpoint to register, list, or rotate a webhook URL. The delivery target is a single field, Webhook URL, set on the external application from the Doclift dashboard (the same key you send as X-Api-Key).

A request is refused outright if the calling external application has no webhook URL configured:

422 Unprocessable Content · application/json
{
  "error": "Please add a webhook URL to this external application to use asynchronous generation. You can add one from your Doclift.io account."
}

See Asynchronous generation.


When it fires

Once every document_generations entry in the request has finished (each one either success or error), Doclift sends exactly one webhook for the whole request. There is no per-generation webhook and no separate "started" event.


Payload

Your endpoint receives
POST https://yourapp.com/webhooks/doclift
Content-Type: application/json
Accept: application/json
X-Doclift-Signature: sha256=<hex hmac>
POST · application/json
{
  "id": 100004,
  "tag": "Batch#12",
  "type": "asynchrone",
  "timestamp": "2024-01-15T10:35:00+01:00",
  "documents_generations": [
    {
      "id": 100230,
      "tag": "Subscription#102",
      "generated_at": "2024-01-15T10:35:02+01:00",
      "created_at": "2024-01-15T10:35:00+01:00",
      "generation_status": "success",
      "file": {
        "filename": "Contract-1615737313.pdf",
        "url": "https://doclift.s3.eu-west-1.amazonaws.com/d207f8fe.pdf?[...]",
        "size": 40290
      }
    }
  ]
}

The documents_generations entries carry the same fields documented in The document request object. The file url is a signed link that needs no authentication to fetch, valid for 2 hours; after that, fetch the document again through View a document request, whose own file URLs stay valid for 20 hours.


Signature verification

Every webhook request carries X-Doclift-Signature: sha256=<hex hmac>: an HMAC-SHA256 of the raw request body, keyed with your external application's secret_key. That is the same value you send as X-Api-Key; there is no separate signing secret.

Signature verification
computed = "sha256=" + OpenSSL::HMAC.hexdigest(
  "SHA256",
  api_secret_key,
  request.raw_post,
)

valid = ActiveSupport::SecurityUtils.secure_compare(
  computed,
  request.headers["X-Doclift-Signature"].to_s,
)

Compute the HMAC over the raw body, not a re-serialized copy of the parsed JSON. Whitespace or key ordering differences would produce a different signature.


What your endpoint must answer

Respond with an HTTP 2xx status within 3 seconds. Any other status code, or no response inside that window, counts as a failed delivery attempt and feeds the retry policy below.


Retry policy

Two separate systems can retry around a single request, and they answer two different questions. Conflating them will make you misread either one.

Webhook delivery retriesPDF generation retries
Question it answersDid your endpoint acknowledge the webhook?Did generation succeed?
Configurable howwebhooks_replays_count, per organization (default 3); contact Doclift to change itNot caller-configurable
Visible viaNothing in this API (see below)The generation's own generation_status/generation_error
Independent ofWhether the document renderedWhether your endpoint ever answers

Webhook delivery retries apply once generation has already finished and Doclift is trying to hand you the result. A non-2xx response, or a timeout/transport failure, schedules another delivery attempt with exponential backoff:

delay for retry attempt n (1, 2, 3, ...) = min(30 × 2^(n-1), 1800) seconds

30s, 60s, 120s, 240s, ... capped at 30 minutes. webhooks_replays_count (see User info) is the number of retries on top of the first attempt. A default of 3 means up to 4 delivery attempts in total before Doclift gives up. A value of 0 or less disables retrying entirely.

PDF generation retries happen earlier and independently, before there is anything to deliver. This has nothing to do with your webhook endpoint and nothing to do with webhooks_replays_count. A document that renders successfully still triggers exactly one, ordinary webhook delivery once it's done.


Failure visibility

The document request's status field reflects generation outcome (success once every generation succeeded, error otherwise). It says nothing about whether the webhook was ever successfully delivered to your endpoint. There is no field or endpoint in this API that reports webhook delivery outcome. If your endpoint never returns a 2xx and retries are exhausted, the underlying document still exists and can be fetched with View a document request.