PDF Generation

Generate PDF documents from HTML content, a live URL, or a saved template.

The default render timeout is 30 seconds. For complex pages with many external resources, you can increase this up to 60 seconds using the timeout option. See the options table below.

Endpoint

POST https://pixdoc.dev/api/v1/pdf

Request Body

Provide exactly one content source (html, url, or template_id) along with an optional options object.

Input Modes

FieldTypeDescription
htmlstringRaw HTML to render as a PDF
urlstringURL of a page to render
template_idstring (UUID)ID of a saved template
template_versionintegerPin a specific template version. If omitted, the latest version is used. Versions auto-increment when template HTML is updated.
variablesobjectKey-value pairs to inject into the template (used with template_id)
optionsobjectRendering options (see below)
metadataobjectArbitrary JSON metadata (max 1KB) attached to the render. Returned in the polling endpoint and webhook payloads. Useful for reconciling renders with your own system (e.g., order IDs, customer references).

You must provide exactly one of html, url, or template_id. Sending more than one or none returns a 400 error.

Options Reference

OptionTypeDefaultDescription
format"A4" | "Letter" | "Legal" | {width, height}"A4"Page size. Use a preset or custom dimensions like {"width": "210mm", "height": "297mm"}
landscapebooleanfalseRender in landscape orientation
marginobject{top: "20mm", right: "20mm", bottom: "20mm", left: "20mm"}Page margins. Each side accepts CSS units (mm, cm, in, px)
printBackgroundbooleantrueInclude background colors and images
displayHeaderFooterbooleanfalseShow header and footer on each page
headerTemplatestringHTML template for the page header. Supports classes: date, title, url, pageNumber, totalPages
footerTemplatestringHTML template for the page footer. Same classes as header
scalenumber1Scale of the content, between 0.1 and 2.0
enableJavaScriptbooleanfalseExecute JavaScript before rendering (useful for charts and dynamic content)
waitForSelectorstring | nullnullCSS selector to wait for before rendering
waitForTimeoutnumber | nullnullMilliseconds to wait before rendering
timeoutnumber30000Maximum render time in milliseconds (1000–60000)

Code Examples

Basic HTML to PDF

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>",
  "metadata": {"order_id": "ORD-1042", "customer": "acme"},
  "options": {
    "format": "Letter",
    "margin": {"top": "25mm", "bottom": "25mm", "left": "20mm", "right": "20mm"}
  }
}' \
-o invoice.pdf

Render a URL

curl -X POST https://pixdoc.dev/api/v1/pdf \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "url": "https://example.com/reports/q4-2025",
  "options": {
    "format": "A4",
    "landscape": true,
    "printBackground": true,
    "enableJavaScript": true,
    "waitForSelector": "#chart-loaded"
  }
}' \
-o report.pdf

Template with Variables

curl -X POST https://pixdoc.dev/api/v1/pdf \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "template_id": "d4e5f6a7-b8c9-0123-4567-89abcdef0123",
  "template_version": 3,
  "variables": {
    "customer_name": "Acme Corp",
    "invoice_number": "INV-2025-042",
    "total": "$1,250.00"
  }
}' \
-o invoice.pdf

Common Patterns

Headers and Footers

Enable displayHeaderFooter and provide HTML templates. Use special CSS classes to insert dynamic values:

{
  "html": "<h1>Contract</h1><p>Terms and conditions...</p>",
  "options": {
    "displayHeaderFooter": true,
    "headerTemplate": "<div style='font-size:10px; text-align:center; width:100%;'>CONFIDENTIAL</div>",
    "footerTemplate": "<div style='font-size:10px; text-align:center; width:100%;'>Page <span class='pageNumber'></span> of <span class='totalPages'></span></div>",
    "margin": { "top": "30mm", "bottom": "30mm" }
  }
}

When using headers and footers, increase the top and bottom margins to prevent content from overlapping with the header/footer area.

Multi-Page Reports

Generate paginated, multi-page reports with running headers and footers. The multi-page-report seed template is a great starting point — it includes a cover page, executive summary, data tables, and multiple sections that flow naturally across 3+ pages.

curl -X POST https://pixdoc.dev/api/v1/pdf \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "template_id": "multi-page-report",
  "variables": {
    "company_name": "Acme Corp",
    "report_title": "Q1 Performance Report",
    "author": "Jane Smith",
    "date": "March 2026",
    "quarter": "Q1 2026"
  },
  "options": {
    "format": "A4",
    "displayHeaderFooter": true,
    "headerTemplate": "<div style=\"font-size:9px;width:100%;padding:0 20mm;display:flex;justify-content:space-between\"><span>Acme Corp</span><span>Q1 Performance Report</span></div>",
    "footerTemplate": "<div style=\"font-size:9px;width:100%;text-align:center\">Page <span class=\"pageNumber\"></span> of <span class=\"totalPages\"></span></div>",
    "margin": {"top": "25mm", "bottom": "20mm", "left": "20mm", "right": "20mm"}
  }
}' \
-o report.pdf

Available CSS classes for header/footer templates:

  • pageNumber — current page number
  • totalPages — total page count
  • date — formatted print date
  • title — document title
  • url — document URL

Header and footer templates render inside the page margins. Set margin.top to at least 20mm to make room for headers, and margin.bottom to at least 15mm for footers. If text is clipped, increase the corresponding margin.

Custom Page Size

Pass a {width, height} object instead of a preset name:

{
  "html": "<div>Custom sized document</div>",
  "options": {
    "format": { "width": "100mm", "height": "150mm" }
  }
}

Waiting for Dynamic Content

If your page loads data asynchronously, use enableJavaScript with waitForSelector or waitForTimeout:

{
  "url": "https://app.example.com/dashboard",
  "options": {
    "enableJavaScript": true,
    "waitForSelector": ".charts-loaded",
    "timeout": 45000
  }
}

Response

A successful request returns the PDF as a binary stream.

Response Headers

HeaderDescription
Content-Typeapplication/pdf
X-Render-Duration-MsTime taken to render, in milliseconds
X-Renders-RemainingNumber of renders left in your monthly quota

Error Responses

Errors return JSON with a status code and error details:

{
  "error": "INVALID_INPUT",
  "message": "Exactly one of 'html', 'url', or 'template_id' must be provided"
}
StatusError CodeMeaning
400INVALID_INPUTMissing or invalid fields in the request body
401UNAUTHORIZEDInvalid or missing API key
429RATE_LIMITEDMonthly render limit exceeded
500RENDER_FAILEDThe renderer encountered an error (e.g., page timeout, invalid HTML)

Async Rendering

For long-running or high-volume PDF generation, use async mode by setting "async": true. The API returns immediately with a 202 Accepted response and a request_id. Optionally add a webhook_url to have the result delivered to your endpoint, or poll for it using the poll_url.

curl -X POST https://pixdoc.dev/api/v1/pdf \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
  "html": "<h1>Invoice #1234</h1>",
  "async": true,
  "webhook_url": "https://example.com/hooks/render",
  "webhook_secret": "whsec_your_secret"
}'

This returns a 202 Accepted response with a request_id you can use to poll for status. See the Webhooks documentation for the full setup guide, payload format, and signature verification.

Poll-Only (No Webhook)

Set "async": true without a webhook_url to poll for the result. The response is the same 202 with a request_id — poll GET /api/v1/renders/{request_id} 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>Invoice #1234</h1>",
  "async": true
}'

Async rendering requires a paid plan (Starter or above).