WeasyPrint as a hosted API
Send HTML, get a PDF rendered by WeasyPrint. 1 credit per render, PDF/A on paid plans, an MCP server, and no Pango stack to install.
Last updated
| Endpoint | POST /v1/weasyprint/render with a JSON body: html (required), filename (optional), pdf_variant (optional, paid plans) |
|---|---|
| Price | 1 credit per render, whatever the page count; rejected and failed calls cost nothing |
| Limits per render | 2 MB of HTML, 50 pages, 20 s with a key and 8 s without |
| MCP server | /mcp/weasyprint/ on the API host, with the render_pdf tool |
| Engine | WeasyPrint 70 with the DejaVu fonts |
pagespool runs WeasyPrint, the open-source engine that lays out HTML
and CSS as print pages. Send an HTML document to POST /v1/weasyprint/render,
and the response body is the PDF. Print CSS works: @page, margin boxes,
page counters and page breaks (CSS support).
No JavaScript runs, and nothing is loaded from the network.
A render costs 1 credit, whatever its page count. Rejected and failed calls cost nothing. One render takes up to 2 MB of HTML and 50 pages, and may run 20 s with an API key or 8 s without. The paid plans add PDF/A-2b and PDF/A-3b output (pricing). The credits are the same ones every other engine here spends.
Quickstart with curl
This call works without an API key, at 10 free credits a day per IP address:
curl -X POST https://api.pagespool.com/v1/weasyprint/render \
-H 'Content-Type: application/json' \
-H "X-API-Key: $PAGESPOOL_KEY" \
-d '{"html": "<h1>Invoice 1</h1><p>Thanks for your business.</p>", "filename": "invoice.pdf"}' \
-o invoice.pdf -w '%{http_code}\n'
A status other than 200 means invoice.pdf holds a JSON error instead of a
PDF (error codes). For PDF/A on
a paid plan, add "pdf_variant": "pdf/a-2b" to the JSON.
Quickstart with Python
httpx or requests is the whole integration. Here the key travels as
HTTP Basic, with the key as the password:
import os
import httpx
resp = httpx.post(
"https://api.pagespool.com/v1/weasyprint/render",
json={"html": "<h1>Report</h1><p>Generated in Python.</p>", "filename": "report.pdf"},
auth=("x", os.environ["PAGESPOOL_KEY"]),
timeout=30,
)
if resp.status_code != 200:
problem = resp.json()
raise RuntimeError(f"{resp.status_code} {problem['code']}: {problem['detail']}")
with open("report.pdf", "wb") as f:
f.write(resp.content)
More in the Python guide and the Node.js guide.
Three ways to send the key
Every engine here takes the key in any of three forms. Pick the one your client supports:
| Form | What to send |
|---|---|
| Header | X-API-Key: YOUR_KEY |
| Bearer token | Authorization: Bearer YOUR_KEY |
| HTTP Basic | The key as the password, any user name: curl -u x:YOUR_KEY or auth=("x", key) |
A client that takes only a URL sends HTTP Basic when the key is in the URL:
https://x:YOUR_KEY@ followed by the API host. Never put the key in the path
or the query string. Keys are created in the dashboard.
A missing or invalid key does not fail a render; it runs at the limit for
calls without a key.
Self-hosted or hosted
WeasyPrint is open source, and you can run it yourself.
| Self-hosted WeasyPrint | Hosted here | |
|---|---|---|
| Setup | Python plus the Pango, HarfBuzz and font packages of your system, kept up to date | One API key |
| Untrusted HTML | WeasyPrint's docs ask you to limit render time and memory per process and to block file and network URLs | Every render runs in its own process, killed at its time limit, with 768 MiB of memory at most; only data: URIs load |
| Memory | Plan for the largest document you render, per parallel render | Not your concern |
| PDF/A | pdf_variant in your own code |
pdf_variant on a paid plan, checked with veraPDF on sample documents |
| Agents | Build a tool around it | The MCP server below |
HTML written for this API also renders on your own WeasyPrint 70 with the DejaVu fonts, so you can move later.
MCP server and free tool
Agents call WeasyPrint through its own MCP server at
https://api.pagespool.com/mcp/weasyprint/, with the render_pdf tool. It takes up to
256 KB of HTML and returns a link to the PDF that works for 15 minutes. Setup
for each client is on the connect page and in the
MCP guide.
To try a document first, paste it into the free tool, without an account.
WeasyPrint is a trademark of its owner; pagespool is not affiliated.
FAQ
- What does a WeasyPrint render cost?
- 1 credit per render, whatever the page count. Rejected and failed calls cost nothing. Every account gets 10 free credits a day and the free plan 100 a month. The credits are shared by all seven engines.
- Can I get PDF/A from the hosted WeasyPrint?
- Yes, on the paid plans. Set pdf_variant to pdf/a-2b or pdf/a-3b. Without a paid plan, the call gets status 403 (feature_not_available) and costs nothing.
- Which header carries the API key?
- Any of three: X-API-Key, Authorization: Bearer, or HTTP Basic with the key as the password. A URL like https://x:YOUR_KEY@ followed by the API host sends Basic.