API Signed render events · 10 min read

Webhooks

Webhooks notify your application when a render succeeds or fails. Use dashboard endpoints for account-level notifications, and per-request webhooks when one asynchronous render should notify a specific endpoint.

Delivery modes

Mode Configured in Best for
Dashboard endpoints BladePDF dashboard Central event handling for all renders in your account.
Template render events Dashboard endpoint Routing automation by the template fields in the payload.
Per-request webhook Laravel render call One-off completion callbacks for a single async render.

Events

Event When it fires
pdf.rendered A render completed successfully.
pdf.failed A render failed validation, timed out, hit a limit, or failed during rendering.

Dashboard endpoints

Create a webhook endpoint in the dashboard when your application should receive render events consistently. Choose the events to subscribe to, copy the signing secret when the endpoint is created, and monitor delivery attempts from the delivery log.

  1. Open Webhooks in the BladePDF dashboard.
  2. Add an endpoint URL, for example https://example.com/webhooks/bladepdf.
  3. Select pdf.rendered, pdf.failed, or both.
  4. Store the generated signing secret in your application environment.
  5. Use the test action to confirm that your endpoint accepts signed events.

Dashboard endpoints receive events for local view renders, raw HTML renders, and dashboard template renders.

Template render events

A dashboard template render emits the same pdf.rendered and pdf.failed events as any other render. The payload identifies the template so your endpoint can route the event to the right workflow.

Route template events
php
 1if (($payload['type'] ?? null) === 'pdf.rendered'
 2    && data_get($payload, 'render.template_name') === 'invoice.standard') {
 3    SyncInvoicePdf::dispatch($payload);
 4}

For local view and raw HTML renders, render.template_id is null. If you call templateName(), that value appears as render.template_name for dashboard filtering and webhook routing.

Per-request webhooks

Use webhook() when a single async render should notify an endpoint in addition to any dashboard-configured endpoints. The URL, secret, and event list are sent with that render request only. Async renders must also call storePdf().

Template render callback
php
 1$submission = BladePDF::fromTemplate('invoice.standard', $context)
 2    ->reference('INV-2026-0042')
 3    ->storePdf()
 4    ->webhook('https://example.com/bladepdf/webhook', 'whsec_request_secret')
 5    ->async();

Limit a per-request webhook to specific events by passing the third argument:

Only successful renders
php
 1BladePDF::fromHtml($html)
 2    ->storePdf()
 3    ->webhook('https://example.com/bladepdf/webhook', 'whsec_request_secret', [
 4        'pdf.rendered',
 5    ])
 6    ->async();
Per-request webhooks use the same delivery system

They are signed, queued, retried, and shown in the dashboard delivery log just like dashboard endpoints. They do not create a reusable dashboard endpoint. See Async Renders for submission and failure semantics.

Payload shape

Webhook payloads are JSON. Every delivery has a unique event id and a nested render summary.

pdf.rendered payload
json
 1{
 2  "id": "0190f7a8-8f7d-7c7b-9b08-2f9878d9c3b2",
 3  "type": "pdf.rendered",
 4  "created_at": "2026-07-01T12:34:56+00:00",
 5  "workspace_id": "0190f78c-93ff-72c4-bb30-9e049e2d7a70",
 6  "render": {
 7    "request_id": "req_abc123",
 8    "status": "success",
 9    "template_id": "0190f790-2bc1-7b2f-9f9c-9dba36bfe2a4",
10    "template_name": "invoice.standard",
11    "render_ms": 420,
12    "queue_ms": 18,
13    "total_duration_ms": 491,
14    "pdf_bytes": 84213,
15    "pdf_url": "https://app.bladepdf.com/render-pdfs/...",
16    "error_message": null,
17    "occurred_at": "2026-07-01T12:34:56+00:00"
18  }
19}
Field Notes
render.request_idStable id for the render request.
render.template_idDashboard template record id for template renders, otherwise null.
render.template_namePublic template identifier such as invoice.standard, or the custom templateName() value for HTML renders.
render.pdf_urlSigned download URL when the generated PDF was stored, otherwise null.
render.error_messagePresent on pdf.failed events.

Delivery headers

Header Description
BladePDF-EventThe event type, such as pdf.rendered.
BladePDF-DeliveryThe delivery id.
BladePDF-TimestampUnix timestamp used in the signature.
BladePDF-SignatureHMAC SHA-256 signature in the form v1=....
Content-Typeapplication/json.

Verify signatures

The signature is computed as HMAC_SHA256(timestamp + "." + rawBody, endpointSecret). Always verify it before processing the event.

routes/api.php
php
 1use Illuminate\Http\Request;
 2use Illuminate\Support\Facades\Route;
 3
 4Route::post('/webhooks/bladepdf', function (Request $request) {
 5    $secret = config('services.bladepdf.webhook_secret');
 6    $timestamp = (string) $request->header('BladePDF-Timestamp');
 7    $signature = (string) $request->header('BladePDF-Signature');
 8    $body = $request->getContent();
 9
10    $expected = 'v1=' . hash_hmac('sha256', $timestamp . '.' . $body, $secret);
11
12    abort_unless(hash_equals($expected, $signature), 401);
13
14    $payload = json_decode($body, true, flags: JSON_THROW_ON_ERROR);
15
16    match ($payload['type'] ?? null) {
17        'pdf.rendered' => ProcessRenderedPdf::dispatch($payload),
18        'pdf.failed' => ProcessFailedPdf::dispatch($payload),
19        default => null,
20    };
21
22    return response()->noContent();
23});
Use the raw request body

Do not re-encode JSON before verifying. Signature verification must use the exact raw body bytes received by your endpoint.

Signing secrets

Dashboard endpoints get a generated secret when the endpoint is created or rotated. Per-request webhooks use the secret you pass to webhook(). Store secrets in environment variables and rotate them if they are exposed.

Retries

BladePDF retries failed deliveries up to five attempts. Retry delays are approximately 1 minute, 5 minutes, 15 minutes, 1 hour, and 6 hours. A dashboard endpoint is marked failing after repeated failures.

Delivery log retention

Delivery attempts (status, response code, latency, response snippet) are visible in the dashboard delivery log for 90 days and are deleted automatically afterwards. If you need a longer delivery audit trail, record webhook receipts on your side using the payload id.

Idempotency

Webhooks may be delivered more than once. Store the payload id or BladePDF-Delivery header and ignore duplicates.

Endpoint rules

  • Use an https:// URL in production.
  • Return any 2xx response after successfully accepting the event.
  • Process expensive work asynchronously in your own queue.
  • Keep endpoint secrets private.
  • Do not make rendering success depend on the webhook endpoint being online; webhook delivery happens after the render event is recorded.
Was this page helpful?
Let us know if something's missing or unclear.