HTML to PDF API
Post HTML and optional CSS and receive a PDF. The engine implements CSS paged media: page sizes and margins, page breaks, running headers and footers, page counters and cross-reference page numbers. It does not run JavaScript, so it suits server-rendered or templated HTML rather than client-side applications.
Send HTML, get a PDF
With theme set to none your HTML and CSS are rendered as-is, plus the page size you ask for.
POST https://papertype.dev/v1/pdf
Authorization: Bearer dp_your_key
Content-Type: application/json
{
"html": "<h1>Statement</h1><table><thead><tr><th>Date</th><th>Amount</th></tr></thead><tbody><tr><td>2026-10-01</td><td>$120.00</td></tr></tbody></table>",
"css": "@page { size: Letter; margin: 20mm } body { font-family: Carlito, sans-serif } thead { display: table-header-group }",
"theme": "none",
"filename": "statement.pdf"
}Leave theme at clean, report, minimal or letter and your HTML is wrapped in that theme's typography, with optional cover page, page numbers and running header or footer text from the same request fields.
A successful call returns 200 with an application/pdf body and the headers X-Pages, X-Quota-Used and X-Quota-Limit. Errors are JSON: 400 when neither html nor markdown is present, 401 for a bad key, 413 when the source is over 2 MB, 422 when the document cannot be rendered (the message says why), and 429 when the monthly quota is reached.
Paged-media CSS you can rely on
@page { size: A4; margin: 18mm }, plus named pages and:firstfor a different first page.- Margin boxes:
@page { @top-right { content: "Confidential" } @bottom-center { content: counter(page) " / " counter(pages) } }. - Break control:
break-before: page,break-inside: avoidon rows and figures,orphansandwidows. - Cross references with real page numbers:
a::after { content: target-counter(attr(href), page) }, and dotted leaders withleader("."). thead { display: table-header-group }repeats a table header on every page the table spans.- Flexbox for layout. Test anything intricate on the free plan first; that is what it is for.
Images and fonts without a network
The renderer has no network access. Images, fonts and stylesheets at external URLs are never fetched; inline them as data: URIs. A request that references an external URL fails with a 422 that names the URL, rather than silently dropping the asset.
<img src="data:image/png;base64,iVBORw0KGgo..." alt="Logo" style="height:14mm">Installed fonts: DejaVu, Liberation, Noto, Carlito and Caladea. Embed any other font with an @font-face rule whose src is a data: URI.
Limits
- No JavaScript is executed. Send the final HTML; anything a script would have drawn or filled in will not appear.
- 2 MB of source per request, 300 pages per document, 2 concurrent renders per account.
- Free-plan output carries a small
papertype.devfooter mark. Paid plans (from $9/month) do not.
Pricing
Plans are capped. When a plan's monthly document count is reached the API returns 429 until you upgrade or the month rolls over; there is no overage billing.
- Free: 50 documents/month, footer mark on output, no card required.
- Starter: $9/month, 500 documents, no mark.
- Pro: $29/month, 3,000 documents.
- Scale: $79/month, 15,000 documents.
Every response includes X-Quota-Used and X-Quota-Limit headers so you can watch usage without polling. Details on the pricing page.
Questions
Does the API execute JavaScript?
No. Produce the final HTML on your side (server-side templates work well) and send that. Charts or content that a script would draw must be rendered to SVG or an image first and inlined.
Can I link an external stylesheet or web font?
No. External URLs are never fetched, by design. Inline the CSS in the css field or a <style> element, and embed fonts via @font-face with data: URIs. DejaVu, Liberation, Noto, Carlito and Caladea are installed.
Which page sizes are available?
A4, Letter, Legal and A5 through the page_size field. Any other size can be set with an @page { size: ... } rule in css, which is applied after the theme.
How large can a document be?
2 MB of source per request and 300 pages per output. Requests over the size limit return 413; documents over the page limit return 422.
Why did my render fail with an error about an external resource?
Something in the HTML (an img, a stylesheet link, a CSS url()) points at an http or https address. Replace it with a data: URI or remove it; the error message includes the offending URL.
Related
Free previews carry a watermark and are deleted after 24 hours. Free API output carries a footer mark. The renderer runs no JavaScript and never fetches external URLs. Privacy · Terms · Refunds