Webhooks
Async rendering processes jobs in the background instead of blocking the HTTP connection. Enable it by setting "async": true in your request. Optionally, add a webhook_url to have PixDoc POST the result to your endpoint when the render completes. You can always poll for the result regardless of whether you set a webhook.
Async rendering is available on the Starter plan and above. Free plan requests that include "async": true will receive a 403 Forbidden response.
Enabling Async Mode
Set "async": true in your request body to enable async mode. The API returns immediately with a 202 Accepted response containing a request_id and poll_url.
Optionally, you can also include:
webhook_url— PixDoc will POST the result to this endpoint when the render completes. Use withwebhook_secretfor signature verification.- Polling — Use the
poll_urlfrom the 202 response to check status at any time. This works whether or not you set a webhook.
You can use both together: webhook as primary delivery, polling as fallback.
With Webhook
Set "async": true and add a webhook_url to receive the result via webhook delivery. You can optionally provide a webhook_secret to enable signature verification.
curl -X POST https://pixdoc.dev/api/v1/pdf \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<h1>Invoice #1042</h1><p>Amount: $250.00</p>",
"async": true,
"webhook_url": "https://your-app.com/webhooks/pixdoc",
"webhook_secret": "whsec_your_secret_here",
"options": {
"format": "Letter"
}
}'Poll-Only (No Webhook)
Set "async": true without a webhook_url to queue the render and poll for the result:
curl -X POST https://pixdoc.dev/api/v1/pdf \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"html": "<h1>Hello</h1>",
"async": true
}'202 Response
When async mode is enabled, the API returns immediately with a 202 Accepted status:
{
"request_id": "req_abc123def456",
"status": "queued",
"message": "Render queued."
}
Webhook Payload
Once the render completes, PixDoc sends a POST request to your webhook_url with a JSON payload. The event field indicates whether the render succeeded or failed.
render.completed
{
"event": "render.completed",
"request_id": "req_abc123def456",
"status": "completed",
"metadata": {"order_id": "ORD-1234", "customer": "acme"},
"output_url": "https://store.pixdoc.dev/renders/req_abc123def456.pdf",
"duration_ms": 1230,
"created_at": "2026-03-28T12:00:00Z",
"completed_at": "2026-03-28T12:00:01Z"
}
The output_url is a signed URL valid for 24 hours. Download the file before it expires.
render.failed
{
"event": "render.failed",
"request_id": "req_abc123def456",
"status": "failed",
"metadata": {"order_id": "ORD-1234", "customer": "acme"},
"error": {
"code": "RENDER_FAILED",
"message": "Page timed out after 30000ms"
},
"created_at": "2026-03-28T12:00:00Z",
"failed_at": "2026-03-28T12:00:31Z"
}
Verifying Signatures
If you provide a webhook_secret in your request, PixDoc signs every webhook delivery with an HMAC-SHA256 signature in the X-PixDoc-Signature header. Always verify this signature to ensure the payload was sent by PixDoc and has not been tampered with.
const crypto = require('crypto');
// Use the raw request body (before JSON parsing)
const signature = req.headers['x-pixdoc-signature'];
const expected = 'sha256=' + crypto
.createHmac('sha256', webhookSecret)
.update(rawBody)
.digest('hex');
if (signature !== expected) {
throw new Error('Invalid signature');
}Always verify signatures against the raw request body, not the parsed JSON. Parsing and re-serializing may change the byte representation and cause verification to fail.
Polling Fallback
If your webhook endpoint is unavailable or you need to check the status of a render manually, you can poll the render status endpoint.
GET https://pixdoc.dev/api/v1/renders/:requestId
curl https://pixdoc.dev/api/v1/renders/req_abc123def456 \
-H "Authorization: Bearer YOUR_API_KEY"Poll Response
{
"request_id": "req_abc123def456",
"status": "completed",
"metadata": {"order_id": "ORD-1234", "customer": "acme"},
"output_url": "https://store.pixdoc.dev/renders/req_abc123def456.pdf",
"duration_ms": 1230,
"created_at": "2026-03-28T12:00:00Z",
"completed_at": "2026-03-28T12:00:01Z"
}
Retry Behavior
If your webhook endpoint does not respond with a 2xx status code, PixDoc retries delivery up to 3 times with exponential backoff:
| Attempt | Delay |
|---|---|
| 1st retry | 5 seconds |
| 2nd retry | 30 seconds |
| 3rd retry | 2 minutes |
After all retries are exhausted, the webhook delivery is marked as failed. You can still retrieve the render result using the polling endpoint.
Your webhook endpoint should return a 2xx response as quickly as possible. Process the payload asynchronously to avoid timeouts. PixDoc waits up to 10 seconds for a response before considering the delivery failed.
Plan Requirements
Async rendering with webhooks is available on the Starter plan and above.
| Plan | Webhooks |
|---|---|
| Free | Not available (returns 403) |
| Starter | Included |
| Pro | Included |