DynamicDocumentAPI

PDF options

Paper sizes, margins, scaling, print behaviour, metadata, accessibility and PDF/UA, PDF/A archiving, attachments, protection and wait strategies for PDF output.

View as Markdown

PDF options control how a page is printed: its size, margins, what is waited for and what metadata the file carries. Send them as output.pdf in a render request, or as pdf in the convenience endpoints.

{
  "input": { "type": "template", "template_id": "tpl_01J9ZK3M7Q8V5W2X4Y6Z8A0B1C" },
  "data": { "number": "2026-0042" },
  "output": {
    "format": "pdf",
    "pdf": {
      "paper": { "size": "A4" },
      "margin": { "top": "20mm", "right": "15mm", "bottom": "20mm", "left": "15mm" },
      "print_background": true
    }
  }
}

Templates store their own defaults, set in the editor's Options tab. Options you send with a request override the template's defaults.

A PDF template can also store a default e-invoice, einvoice: {"profile": "EN16931", "invoice_path": "invoice"} next to pdf in its options, set in the Options tab under E-invoice (ZUGFeRD / Factur-X). Every render of it is then a Factur-X / ZUGFeRD PDF/A-3b unless the request sends its own output.einvoice, or "einvoice": null to render a plain PDF. On plans without e-invoicing it is skipped with the warning einvoice_skipped_plan. See Make a template an e-invoice by default.

Page setup

OptionTypeDefaultDescription
paper.sizestring"A4"A named size: A0 to A6, B4, B5, Letter, Legal, Tabloid or Ledger
paper.width, paper.heightstring—A custom size instead of size, as CSS lengths, for example "80mm" and "200mm"
orientationstring"portrait"portrait or landscape. Landscape swaps width and height.
margin.top, margin.right, margin.bottom, margin.leftstringnot setPage margins as CSS lengths. When a header or footer is enabled and margins are not set, the margin follows its height.
scalenumber1.0Scales the rendered content between 0.1 and 2.0
prefer_css_page_sizebooleanfalseTake the page size from the CSS @page rule instead of paper, which also allows different sizes per page
single_pagebooleanfalseProduce a single continuous page as tall as the content
page_rangesstringall pagesKeep only these pages, for example "1-3,5"

Paper sizes

SizeMillimetresInches
A0841 × 118933.11 × 46.81
A1594 × 84123.39 × 33.11
A2420 × 59416.54 × 23.39
A3297 × 42011.69 × 16.54
A4210 × 2978.27 × 11.69
A5148 × 2105.83 × 8.27
A6105 × 1484.13 × 5.83
B4250 × 3539.84 × 13.90
B5176 × 2506.93 × 9.84
Letter215.9 × 279.48.5 × 11
Legal215.9 × 355.68.5 × 14
Tabloid279.4 × 431.811 × 17
Ledger431.8 × 279.417 × 11

Custom sizes are useful for labels and receipts:

{ "paper": { "width": "4in", "height": "6in" } }

CSS length units

Sizes and margins are CSS length strings with an explicit unit:

UnitMeaning
mm, cmMillimetres, centimetres
inInches
ptPoints, 1/72 inch
pcPicas, 12 points
pxCSS pixels, 1/96 inch

For example "20mm", "0.75in" and "48px" are valid; a bare number is not.

Content and print behaviour

OptionTypeDefaultDescription
print_backgroundbooleantruePrint background colours and images
emulate_mediastring"print"print applies your @media print rules; screen renders the page as a browser screen would, which is often what you want for url input
javascriptbooleantrueRun scripts in the page. Turn it off for untrusted HTML or to speed up renders.
timezonestring"UTC"IANA time zone used by scripts in the page
localestring"en-US"Locale used by scripts in the page, for example for Intl formatting

Backgrounds only print when the element also allows it in CSS. Add print-color-adjust: exact (with the -webkit- prefixed property for older engines) to elements with coloured backgrounds.

Headers and footers

header and footer take the same fields. Headers and footers explains both modes in detail.

OptionTypeDefaultDescription
header.enabledbooleanfalseDraw the header on every page
header.htmlstringnoneHTML for the header, with template expressions and the page, pages, date, title and url classes
header.left, header.center, header.rightstringnoneSimple text mode, with the {{page}}, {{pages}}, {{date}} and {{title}} tokens
header.font_sizestring"9px"Base font size of the header document
header.heightstring"15mm"Height reserved for the header

Accessibility and archiving

OptionTypeDefaultDescription
taggedbooleanfalseProduce a tagged PDF with a structure tree, so assistive technology can read the document. Use semantic HTML (headings, lists, table headers, alt text) and set metadata.lang. The render's result.conformance.pdfua holds a PDF/UA-1 report for information.
pdfuastringnull"1": deliver a PDF/UA-1 document, validated with veraPDF. The render fails if the check fails. Implies tagged. See PDF/UA.
outlinebooleanfalseAdd PDF bookmarks generated from the h1 to h6 headings
pdfastringnull"2b" or "3b": convert the PDF to PDF/A and validate it with veraPDF. See PDF/A.
attachmentsarray[]Up to 20 files embedded in the PDF. See Attachments.

Compliance features

PDF/UA and PDF/A output and e-invoices (Factur-X, ZUGFeRD and XRechnung) are available, each with a validation report.

PDF/A

PDF/A (ISO 19005) is the standard for PDFs that must stay readable for decades, such as invoices, contracts and statements. Set pdfa and the engine converts the printed PDF, then validates it with veraPDF:

{
  "input": { "type": "template", "template_id": "tpl_01J9ZK3M7Q8V5W2X4Y6Z8A0B1C" },
  "data": { "number": "2026-0042" },
  "output": {
    "format": "pdf",
    "pdf": { "pdfa": "2b", "metadata": { "title": "Invoice 2026-0042", "lang": "de-DE" } }
  }
}
LevelStandardUse it for
2bPDF/A-2b (ISO 19005-2), conformance level B: reliable visual appearanceArchiving business documents
3bPDF/A-3b (ISO 19005-3)The same as 2b, plus embedded files of any type. E-invoices use it to carry their XML.

The conversion adds an sRGB output intent and writes the PDF/A identification and the document metadata into XMP. It doesn't render the page again, so text, images and layout stay as printed. PDF/A output costs no additional renders. It is included in the Growth plan and higher; on Free and Starter, pdfa fails with 402 plan_feature_unavailable.

What to know:

  • Fonts must be embedded. If a font can't be embedded, the render fails with 422 pdfa_conversion_failed and the message names the font.
  • No encryption. PDF/A forbids it, so protect together with pdfa fails with 400 validation_error.
  • Report. result.conformance.pdfa on the render holds the level, the status (passed, failed or unavailable) and any findings. If veraPDF finds the file non-compliant, the render fails with pdfa_conversion_failed, costs nothing, and the failed rules are listed in the report. See validation report.
  • Unavailable validator. If veraPDF doesn't answer in time, the file is delivered unvalidated, with the warning pdfa_validation_unavailable and status: "unavailable".
  • Test renders. The TEST watermark is drawn as vector outlines and stamped before the conversion, so a test PDF is conformant too and the report describes the delivered file.

Convert an existing PDF

POST /v1/pdf-tools/pdfa converts a PDF that wasn't rendered by Dynamic Document API and validates the result:

curl https://api-eu.dynamicdocumentapi.com/v1/pdf-tools/pdfa \
  -H "Authorization: Bearer $DYNAMIC_DOCUMENT_API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -H "Content-Type: application/json" \
  -d '{ "source": { "url": "https://example.com/contract.pdf" }, "level": "2b", "filename": "contract-pdfa.pdf" }'
FieldDescription
sourceThe PDF. Exactly one of url, render_id (with an optional file_id), upload_id or data_uri
level2b or 3b
filenameName of the converted file

The response is a render with the converted file and the report in result.conformance.pdfa. It accepts the same mode, delivery, webhook, reference, metadata and test fields as the other PDF tools. Conversion is best effort: it can't embed fonts the source doesn't contain, and it can't process encrypted PDFs. Either fails with pdfa_conversion_failed. A conversion is billed as 1 render, and failed ones cost nothing. Like pdfa, this endpoint needs the Growth plan or higher.

PDF/UA

PDF/UA (ISO 14289-1) is the standard for accessible PDFs: screen readers and other assistive technology can read them in the right order, with headings, lists, tables, link texts and image descriptions. Set pdfua to "1" and the render either delivers a PDF that passes veraPDF's PDF/UA-1 checks or fails:

{
  "input": { "type": "template", "template_id": "tpl_01J9ZK3M7Q8V5W2X4Y6Z8A0B1C" },
  "data": { "number": "2026-0042" },
  "output": {
    "format": "pdf",
    "pdf": { "pdfua": "1", "metadata": { "title": "Invoice 2026-0042", "lang": "en-GB" } }
  }
}

After rendering, Dynamic Document API fixes what the browser's tagging leaves open: link descriptions, list structure, headers and footers marked as artifacts that screen readers skip, and the PDF/UA identification. What only your template can provide:

  • A title and a language. Set metadata.title or a <title> element, and metadata.lang or <html lang>. With pdfua there is no default language: a document without one fails the check.
  • Text alternatives. alt text on meaningful images, and alt="" on decorative ones.
  • Structure. Real tables with <th scope>, headings in order, and lists as <ul> or <ol>.

Content that is hidden from the accessibility tree (aria-hidden, alt="", CSS content, borders) becomes a decoration that screen readers skip, so meaningful text belongs in the markup.

What to know:

  • Report. result.conformance.pdfua holds the standard, the status (passed, failed or unavailable) and the rules that failed. A render that fails the check fails with 422 pdfua_validation_failed and the report, and costs nothing.
  • Unavailable validator. If veraPDF doesn't answer in time, the file is delivered unvalidated, with the warning pdfua_validation_unavailable and status: "unavailable".
  • Limits of the check. veraPDF checks what a machine can check. Whether alt text is meaningful and the reading order is right is yours to review.
  • Combinations. pdfua works with pdfa, e-invoices, attachments and protect, which keeps access for assistive technology. PDFs from canvas templates can't be PDF/UA (400 validation_error).
  • Previews and publishing. Editor previews show the report but never fail. Publishing warns when the template's test render fails the check.
  • Plan. PDF/UA is included in the Growth plan and higher; on Free and Starter, pdfua fails with 402 plan_feature_unavailable.

Attachments

attachments embeds files in the PDF, for example the supporting documents of an invoice. Each entry has:

FieldDescription
url, data_uri or upload_idExactly one source. A url is fetched like an asset. A data_uri may be at most 5 MB, and all of them together at most 8 MB of base64; use an upload for more.
nameFile name in the PDF: 1 to 255 characters, without /, \ or control characters, and unique in the document, ignoring case
mime_typeOptional. Derived from the name's extension, else application/octet-stream
descriptionOptional description shown by PDF readers
relationshipOptional: Source, Data, Alternative, Supplement or Unspecified (the default)
{
  "output": {
    "format": "pdf",
    "pdf": {
      "attachments": [
        { "url": "https://example.com/timesheet.csv", "name": "timesheet.csv", "relationship": "Supplement" }
      ]
    }
  }
}

Up to 20 files, each at most 10 MiB and 25 MiB together. A file that can't be fetched fails the render with 422 attachment_failed, which names it.

Attachments work with plain PDFs and with pdfa: "3b", where they sit next to an e-invoice's XML. pdfa: "2b" can't carry them (400 validation_error), and an attachment can't take the name of the embedded e-invoice (factur-x.xml, xrechnung.xml). With protect, the files are embedded before encryption. Editor previews and test renders leave attachments out. Uploads expire after 24 hours, so a template's default attachments use url or data_uri.

Metadata

OptionTypeDefaultDescription
metadata.titlestringnoneDocument title stored in the PDF
metadata.authorstringnoneAuthor
metadata.subjectstringnoneSubject
metadata.keywordsarray of strings[]Keywords
metadata.creatorstringnoneThe application that created the document
metadata.langstring"en"Document language as a BCP 47 tag, such as "de-DE". It sets the lang attribute of the rendered HTML and the document language in the PDF. With pdfua there is no default: set it here or in <html lang>.

Security

OptionTypeDefaultDescription
protect.user_passwordstringnonePassword needed to open the document
protect.owner_passwordstringnonePassword needed to change permissions
protect.permissions.printbooleantrueAllow printing
protect.permissions.print_high_resbooleantrueAllow printing at full quality
protect.permissions.copybooleantrueAllow copying text and images
protect.permissions.modifybooleanfalseAllow changing the content
protect.permissions.annotatebooleanfalseAllow adding comments and annotations
protect.permissions.fill_formsbooleantrueAllow filling in form fields
protect.permissions.assemblebooleanfalseAllow inserting, rotating and deleting pages

Protecting a document restricts editing, not reading: a permission you leave out keeps its default. To protect an existing PDF, use the protect tool.

Documents are encrypted with AES-256. Passwords are part of the request body, so keep them out of logs on your side and use request-log redaction rules if you enable request logging. Protection can't be combined with pdfa or an e-invoice, because PDF/A forbids encryption. With pdfua, protection keeps the permission that lets assistive technology read the text.

Waiting and scripting

Rendering starts once the page is ready. Choose a strategy that matches how your page loads:

wait.untilReady when
loadThe page's load event has fired
networkidleNo request has been in flight for 500 ms. The default, and a good fit for pages with remote images or fonts.
selectorAn element matching wait.selector exists
ready_flagThe page has set window.__DYNAMIC_DOCUMENT_API_READY__ = true
delaywait.delay_ms milliseconds have passed after load
OptionTypeDefaultDescription
wait.untilstring"networkidle"Wait strategy, see above
wait.selectorstringnoneCSS selector to wait for, with until: "selector"
wait.delay_msnumber0Extra delay in milliseconds, up to 10000
wait.timeout_msnumber30000Maximum time for each wait step

After the wait condition, the renderer always waits for web fonts to load and images to decode before printing, so a fixed delay is rarely necessary. When a wait step times out, the render continues with the page as it is and records a warning, so check the render's warnings if output looks incomplete. A render that cannot continue fails with 422 wait_timeout.

For pages that build content with JavaScript, such as charts, set the ready flag when you are done:

<script>
  renderChart(data).then(() => {
    window.__DYNAMIC_DOCUMENT_API_READY__ = true;
  });
</script>
{ "wait": { "until": "ready_flag", "timeout_ms": 20000 } }

Examples

An A4 invoice with a footer and metadata:

{
  "paper": { "size": "A4" },
  "margin": { "top": "18mm", "right": "16mm", "bottom": "22mm", "left": "16mm" },
  "print_background": true,
  "footer": {
    "enabled": true,
    "html": "<div style=\"width:100%;padding:0 16mm;display:flex;justify-content:space-between;font-size:8pt;color:#555\"><span>Example GmbH</span><span>Page <span class=\"page\"></span> of <span class=\"pages\"></span></span></div>",
    "height": "14mm"
  },
  "metadata": { "title": "Invoice 2026-0042", "author": "Example GmbH", "lang": "de-DE" }
}

An 80 mm receipt on one continuous page, where the declared height is replaced by the content height:

{
  "paper": { "width": "80mm", "height": "200mm" },
  "margin": { "top": "4mm", "right": "4mm", "bottom": "4mm", "left": "4mm" },
  "single_page": true
}

A landscape report with bookmarks and a tagged structure:

{
  "paper": { "size": "A3" },
  "orientation": "landscape",
  "scale": 0.9,
  "outline": true,
  "tagged": true,
  "metadata": { "title": "Quarterly report", "lang": "en-GB" }
}

A shipping label at 4 × 6 inches, printed edge to edge:

{
  "paper": { "width": "4in", "height": "6in" },
  "margin": { "top": "0mm", "right": "0mm", "bottom": "0mm", "left": "0mm" },
  "print_background": true
}

A protected document with printing allowed but copying and editing blocked:

{
  "paper": { "size": "A4" },
  "protect": {
    "user_password": "…",
    "owner_password": "…",
    "permissions": { "print": true, "copy": false, "modify": false }
  }
}

On this page