PDF Generation API

PDF generation API for automated, data-driven documents

One REST API for every PDF your product sends: from a template and JSON, raw HTML, a URL or Markdown. Rendered in Chromium, delivered by link, file or webhook.

  • 50 free renders/month
  • No credit card
  • Median render 216 ms

What is a PDF generation API?

A PDF generation API is a web service your application calls to create PDF documents automatically. You send content, such as a template ID with JSON data, raw HTML, a URL or Markdown, and the service renders it and returns the finished PDF. It replaces the PDF library or headless browser you would otherwise build, host and maintain yourself.

PDF generation API key facts
InputsTemplate + JSON, HTML + CSS, URL, Markdown
OutputsPDF; PNG, JPEG or WebP from the same inputs
Rendering engineEngine 2026.4 on Chromium (Chrome 153.0.8010.47), JavaScript on by default
Render timeMedian 216 ms, p95 516 ms, p99 667 ms (queue + processing, excluding network)1
ModesSynchronous, asynchronous with webhooks, batches from JSON or CSV
DeliverySigned URL, binary, base64, or your own S3-compatible bucket (Enterprise)
ReliabilityIdempotency keys, signed webhooks with 8 delivery attempts, automatic retry of browser crashes
PriceFree: 50 renders/month. Paid from €15/month (billed annually) for 3,000 renders, auto top-ups from €6 per 1,000

1. Measured over 1,664 successful renders on engine 2026.4. total_ms = time in the queue plus processing in the worker, excluding API overhead and network transfer. p75 378 ms, p90 478 ms, maximum 2,261 ms.

Four ways to generate a PDF

Pick the input that matches where your content already lives. All four share the same engine, print options, delivery and webhooks, so you can mix them in one product.

Template + JSON

Store the layout once and send only data. Best for documents you create thousands of times: invoices, certificates, statements. Learn more about PDF templates with variables and loops.

HTML + CSS

Send markup your app already renders and get it back as a PDF, with headers, page numbers and web fonts. See the HTML to PDF API.

Markdown

Docs, reports and AI output, styled with a print theme and sanitized by default. Read about Markdown to PDF.

How automated PDF generation works

  1. Your app sends content

    An event in your product, such as a payment, a finished course or a month-end job, triggers one API call.

  2. The engine renders

    Data is merged, the page loads in Chromium, scripts and fonts finish, and the PDF is printed.

  3. You get the file

    In the response, as a signed link, in your storage bucket, or announced by webhook.

Every input is also available through one endpoint, POST /v1/renders, where input.type selects template, HTML, URL or Markdown and output.format selects PDF or an image format:

curl https://api.dynamicdocumentapi.com/v1/renders \
  -H "Authorization: Bearer $DYNAMIC_DOCUMENT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "input":  { "type": "html", "html": "<h1>Welcome, {{ name }}</h1>" },
    "data":   { "name": "Acme Co." },
    "output": { "format": "pdf", "pdf": { "paper": { "size": "Letter" } } },
    "mode": "async",
    "webhook": { "url": "https://example.com/hooks/pdf",
                 "events": ["render.succeeded", "render.failed"] }
  }'

# 202 Accepted → { "id": "rnd_…", "status": "queued" }
const res = await fetch("https://api.dynamicdocumentapi.com/v1/renders", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DYNAMIC_DOCUMENT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    input:  { type: "html", html: "<h1>Welcome, {{ name }}</h1>" },
    data:   { name: "Acme Co." },
    output: { format: "pdf", pdf: { paper: { size: "Letter" } } },
    mode: "async",
    webhook: { url: "https://example.com/hooks/pdf", events: ["render.succeeded", "render.failed"] },
  }),
});
const { id, status } = await res.json(); // 202, status "queued"
import os
import requests

res = requests.post(
    "https://api.dynamicdocumentapi.com/v1/renders",
    headers={"Authorization": f"Bearer {os.environ['DYNAMIC_DOCUMENT_API_KEY']}"},
    json={
        "input":  {"type": "html", "html": "<h1>Welcome, {{ name }}</h1>"},
        "data":   {"name": "Acme Co."},
        "output": {"format": "pdf", "pdf": {"paper": {"size": "Letter"}}},
        "mode": "async",
        "webhook": {"url": "https://example.com/hooks/pdf",
                    "events": ["render.succeeded", "render.failed"]},
    },
    timeout=30,
)
render = res.json()  # 202, render["status"] == "queued"
<?php
$ch = curl_init('https://api.dynamicdocumentapi.com/v1/renders');
curl_setopt_array($ch, [
    CURLOPT_POST           => true,
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_HTTPHEADER     => [
        'Authorization: Bearer ' . getenv('DYNAMIC_DOCUMENT_API_KEY'),
        'Content-Type: application/json',
    ],
    CURLOPT_POSTFIELDS     => json_encode([
        'input'   => ['type' => 'html', 'html' => '<h1>Welcome, {{ name }}</h1>'],
        'data'    => ['name' => 'Acme Co.'],
        'output'  => ['format' => 'pdf', 'pdf' => ['paper' => ['size' => 'Letter']]],
        'mode'    => 'async',
        'webhook' => ['url' => 'https://example.com/hooks/pdf',
                      'events' => ['render.succeeded', 'render.failed']],
    ]),
]);
$render = json_decode(curl_exec($ch), true); // 202, status "queued"

Dynamic PDFs from your own data

"Dynamic" means the document changes with the data, not only the values in it. A template decides what appears, how often and in which format:

  • Variables for names, numbers and dates, escaped automatically.
  • Loops for line items, participants or report rows, in tables that continue over as many pages as needed with the header repeated.
  • Conditions for optional sections, such as a discount line, a "Paid" stamp or a clause for one country.
  • Locale formatting for currencies, numbers and dates, based on Unicode CLDR, so one template serves every market.
  • Codes: QR codes and 16 barcode types generated from your data.

What teams generate

  • Invoices and receipts from payment events, in the customer's currency. Teams automate invoice PDFs with one call per payment and a batch at month-end.
  • Reports and statements with charts drawn by JavaScript, captured only when every chart is ready.
  • Certificates and tickets for each participant, with a QR code for verification or check-in, as PDF and as image.
  • Contracts and offers assembled from clauses, pinned to the template version the customer signed.

Built for production

Generating one PDF is easy. Generating the right PDF every time, under load, with retries and without duplicates, is the part teams underestimate.

Sync, async and batches

Synchronous by default. If a render outlasts your plan's sync limit, the API answers 202 and keeps going instead of failing. Use "mode": "async" for long jobs and batches for thousands of documents from one template.

Signed webhooks with retries

Webhooks follow the Standard Webhooks format: HMAC-SHA256 signatures in webhook-signature, with a timestamp against replay. A delivery your server does not accept is tried up to eight times over about 28 hours, and can be replayed by hand.

No duplicates on retry

Send an Idempotency-Key header, such as your invoice number. A retried request within 24 hours returns the original render instead of a second document.

Test and live keys

Test keys render for free with a "TEST" watermark and keep files for one day, so development and CI never touch your quota or your customers' documents.

Build vs. buy: what your own PDF pipeline really costs

Running headless Chrome yourself is a reasonable choice. It is also more work than the first prototype suggests. Here is what each part involves.

Building your own PDF pipeline compared with using the API
Part Self-built with headless Chrome Dynamic Document API
First PDFA day with Puppeteer or PlaywrightMinutes with an API key
Production serviceQueue, worker pool, timeouts, file storage, signed links, webhooksIncluded
Browser updatesChrome ships a major release every four weeks; you test and roll out each oneWe test and pin engine releases
Fonts and rendering bugsMissing fonts, fallback glyphs, cut table rows, late-loading chartsFont loading, wait conditions and page-break handling built in
SecurityBlocking internal network access from user-supplied HTML is on youPrivate and internal addresses blocked for every fetch
TemplatesTemplates in your code base, deployed with your appVersioned templates with rollback, changeable without a deploy
Best whenData must never leave your network, or volume is very high and steadyYou want reliable PDFs without operating browsers

PDF generation API pricing

Free

€0

50 renders per month, full REST API. No credit card.

Starter

€15 / month

3,000 renders per month, billed annually (€19 billed monthly). About €0.005 per render.

Growth (€47/month, 15,000 renders), Pro (€119/month, 50,000) and Scale (€319/month, 200,000) are billed annually; Enterprise starts at €1,500. When a paid plan runs low, 1,000 renders are added automatically at €6 to €2 per 1,000, so a pipeline never stops at month end. See the full pricing, or talk to sales about higher volumes.

FAQ

PDF generation API: frequently asked questions

What's the difference between a PDF generation API and an HTML to PDF API?

HTML to PDF is one way to generate a PDF: you send finished markup. A PDF generation API covers the whole job: it also fills stored templates with JSON, captures URLs and converts Markdown, and adds what production needs, such as async jobs, webhooks, batches and file delivery.

How many PDFs can I generate per month?

The free plan includes 50 renders a month. Paid plans start at 3,000 renders a month for €15 billed annually and go to 200,000 on Scale; Enterprise starts at 1,000,000. When a paid plan runs low, 1,000 renders are added automatically at the plan's top-up price. On the free plan, render packs start at €50 for 10,000 renders.

Can I generate PDFs in bulk?

Yes. A batch takes one template and a list of items, or a CSV file, and creates one PDF per item. Progress and completion arrive by webhook, failed items can be retried on their own, and all PDFs can be merged into one file. Batches are available on paid plans.

What happens when a render fails?

You get an error with a machine-readable code, such as a template error with line and column, a navigation failure or a timeout, plus a render.failed webhook if you subscribed. Browser crashes are retried automatically on a fresh browser. Errors in your template or data are not retried, because the result would be the same.

Where is my data processed?

Render payloads and generated files stay in the region of the API host you call. Files are delivered through signed, expiring links, and you decide how many days they are kept, up to your plan's maximum.

Can the same API generate images?

Yes. Every input that produces a PDF can also produce PNG, JPEG or WebP, for example a certificate as a printable PDF and as an image for social sharing, or a screenshot of a URL.

Generate your first PDF free

50 renders a month on the free plan, no credit card, auto top-ups on paid plans, no browser to run.

Start free