PDFDispatch Docs

Webhooks

Instead of waiting for the PDF, give the API a URL. It answers at once with 204 No Content, makes the file, and sends it to your server.

When to use them

  • Your client cannot or should not hold a connection open for many seconds (serverless functions, request queues).
  • You already have a job queue and want the result to arrive as a request to your app.

A webhook does not make conversions faster, and does not lift the 60-second limit. The request counts as one PDF when it is accepted with 204, also if the job fails later.

Headers

Add these headers to any conversion or PDF tool request (but not to the metadata and bookmarks reads, which have no file to send):

HeaderTypeDefaultWhat it does
Webhook-Url requiredheader–Where the result goes, as the body of an HTTP request.
Webhook-Events-Urlheader–Where a short JSON event goes after the delivery: webhook.success, or webhook.error with the status and message. Send this one or Webhook-Error-Url (or both).
Webhook-Error-Urlheader–Where a JSON error goes when the job fails. The older way; prefer Webhook-Events-Url.
Webhook-MethodheaderPOSTPOST, PUT or PATCH for the call to Webhook-Url.
Webhook-Error-MethodheaderPOSTThe same for Webhook-Error-Url. Events always use POST.
Webhook-Extra-Http-Headersheader (JSON object)–Headers we add to every call to your URLs, for example {"Authorization": "Bearer your-own-secret"}. A Content-Disposition here replaces ours.

Example

curl --fail-with-body \
  --header "Authorization: Bearer $PDD_KEY" \
  --header "Webhook-Url: https://app.example.com/hooks/pdf?invoice=1042" \
  --header "Webhook-Events-Url: https://app.example.com/hooks/pdf-events" \
  --header 'Webhook-Extra-Http-Headers: {"Authorization": "Bearer your-own-secret"}' \
  --header "Output-Filename: invoice-1042" \
  --form files=@index.html \
  https://api.pdfdispatch.com/v1/convert/html

The answer is 204 with an X-Request-Id. Keep the id: every call that follows carries it.

What your server receives

The file, at Webhook-Url (with Webhook-Method, POST by default):

  • the body is the file itself (PDF, image or ZIP), not multipart;
  • Content-Type and Content-Length as usual, Content-Disposition: attachment; filename="invoice-1042.pdf";
  • X-Request-Id: the id from the 204 answer;
  • your Webhook-Extra-Http-Headers.

An event, at Webhook-Events-Url, always POST, JSON, after the delivery:

{ "event": "webhook.success", "correlationId": "0192f7c4-5b7e-7d3a-9c41-2f0e8a6b1d55", "timestamp": "2026-10-26T09:41:07.512Z" }
{
  "event": "webhook.error",
  "correlationId": "0192f7c4-5b7e-7d3a-9c41-2f0e8a6b1d55",
  "timestamp": "2026-10-26T09:41:07.512Z",
  "error": { "status": 400, "message": "Invalid form data: form field 'paperWidth' is invalid ..." }
}

correlationId is the request id. On an error at Webhook-Error-Url, the body is {"status": 400, "message": "..."}, sent with Webhook-Error-Method.

Answering, and retries

Answer with any 2xx once you have stored the file. A failed delivery (a network error, 429 or a 5xx from your server) is retried up to four times, with waits growing from 1 to 30 seconds; each try may take up to 30 seconds. A 4xx other than 429 is not retried. Events are sent once and not retried; use them as a signal, not as the only record.

Securing your endpoint

Anyone who knows your webhook URL could post to it. Protect it:

  • Put a secret in Webhook-Extra-Http-Headers ({"Authorization": "Bearer ..."}) and check it on every call. Use a different secret from your PDFDispatch key.
  • Or put an unguessable token in the URL itself, one per job, and accept each token once.
  • Match the X-Request-Id to the request you made before you trust the content.

Your URLs must be on the public internet; private and local addresses are refused with 403 before the job starts (details).