Webhooks

Webhooks let you receive real-time HTTP notifications when async conversions and batch jobs complete. No polling required.

Creating Webhook Endpoints

There are two ways to use webhooks with pdfRelay:

1. Per-request webhooks

Include a webhook_url in your async or batch request:

{
  "html": "<h1>Report</h1>...",
  "webhook_url": "https://your-app.com/webhooks/pdfrelay"
}

2. Account-level webhooks

Configure a default webhook endpoint in your dashboard under Settings → Webhooks. This endpoint receives notifications for all async and batch jobs that do not specify their own webhook_url.

Event Types

EventDescription
job.completedAn async conversion job completed successfully
job.failedAn async conversion job failed
batch.completedAll items in a batch have finished processing
batch.item.completedAn individual item in a batch completed (opt-in)

Webhook Payload

pdfRelay sends a POST request to your webhook URL with a JSON body:

{
  "event": "job.completed",
  "timestamp": "2025-01-15T10:30:02Z",
  "data": {
    "job_id": "job_abc123def456",
    "status": "completed",
    "download_url": "https://api.pdfrelay.com/v1/jobs/job_abc123def456/download",
    "pages": 3,
    "size_bytes": 45678,
    "conversion_ms": 1250
  }
}

HMAC Signature Verification

Every webhook request includes an HMAC-SHA256 signature in the X-PdfRelay-Signature header. Verify this signature to ensure the request came from pdfRelay.

Your webhook signing secret is available in your dashboard under Settings → Webhooks.

Verification Example (Node.js)

import crypto from 'crypto';

function verifyWebhookSignature(
  payload: string,
  signature: string,
  secret: string
): boolean {
  const expected = crypto
    .createHmac('sha256', secret)
    .update(payload)
    .digest('hex');
  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expected)
  );
}

// In your webhook handler:
app.post('/webhooks/pdfrelay', (req, res) => {
  const signature = req.headers['x-pdfrelay-signature'];
  const isValid = verifyWebhookSignature(
    JSON.stringify(req.body),
    signature,
    process.env.PDFRELAY_WEBHOOK_SECRET
  );

  if (!isValid) {
    return res.status(401).json({ error: 'Invalid signature' });
  }

  // Process the webhook event
  const { event, data } = req.body;
  console.log(`Received ${event} for job ${data.job_id}`);

  res.status(200).json({ received: true });
});

Retry Behavior

If your webhook endpoint returns a non-2xx status code or times out (30-second timeout), pdfRelay will retry the delivery with exponential backoff:

AttemptDelay
1st retry1 minute
2nd retry5 minutes
3rd retry30 minutes
4th retry2 hours
5th retry (final)24 hours

After 5 failed attempts, the webhook delivery is marked as failed. You can view failed deliveries and trigger manual retries from the dashboard.

Important

Your webhook endpoint must respond within 30 seconds and return a 2xx status code. Always return a response quickly and process the webhook payload asynchronously if needed.

Webhooks - pdfRelay Docs | pdfRelay