Reference
HTTP API
The n8n node is a thin client over this API. Any HTTP client can call it the same way. Documents are returned as binary in the response body — never hosted at a URL.
Authentication
Send your API key as either header. Create keys in the dashboard under API Keys.
x-api-key: pk_live_your_key
# or
Authorization: Bearer pk_live_your_keyPOST /v1/render
Send a template id or raw html (exactly one), plus data, and get the rendered document back.
Request body
{
"template": "invoice", // one of the starter ids
// OR (mutually exclusive — sending both is INVALID_REQUEST):
"html": "<html>…</html>", // raw HTML; a Handlebars template when data is non-empty
"data": { "any": "json" }, // template variables; missing vars render blank
"format": "pdf", // "pdf" (default) | "png" (PNG returns the FIRST page only)
"options": { // all optional
"pageSize": "A4", // A3 | A4 | A5 | Letter | Legal | Tabloid
"landscape": false,
"margin": { "top": "10mm", "right": "10mm", "bottom": "10mm", "left": "10mm" },
"printBackground": true,
"scale": 1.0 // 0.1 – 2
}
}Success response
200 OK with the binary body — application/pdf or image/png — and these headers:
| Header | Meaning |
|---|---|
x-request-id | Unique id for this render — quote it to support. |
x-pdfmill-pages | Page count of the rendered PDF. |
x-pdfmill-duration-ms | Server-side render time in milliseconds. |
Errors
Any failure returns { "error": { "code", "message", "requestId" } } with the matching HTTP status and the x-request-id header. See the full error table.
Example
curl -s https://api.pdfmill.dev/v1/render \
-H 'content-type: application/json' \
-H 'x-api-key: pk_live_your_key' \
-d '{"template":"invoice","data":{"invoiceNumber":"INV-1","total":42,"currency":"USD"}}' \
-o invoice.pdfHandlebars helpers
{{formatDate value "long"}} and {{formatMoney value "USD"}} — both deterministic (UTC, no locale dependence). See the templates guide.GET /v1/templates
Lists the templates your key can render by id (what the n8n dropdown shows). Auth-gated like every route.
{
"templates": [
{ "id": "invoice", "name": "Invoice", "source": "starter" },
{ "id": "quote", "name": "Quote", "source": "starter" }
]
}GET /healthz
Unauthenticated health probe. 200 with { status: "ok", chrome, pool: { size, live, busy, queued, … } } while a renderer is live; 503 otherwise.
Limits
Each limit returns a named error when exceeded (no silent truncation):
| Limit | Default | Error when exceeded |
|---|---|---|
| Request payload | 2 MB | PAYLOAD_TOO_LARGE |
| Rendered output | 20 MB | OUTPUT_TOO_LARGE |
| Pages per document | 50 | OUTPUT_TOO_LARGE |
| Render wall-clock | 30 s | RENDER_TIMEOUT |
| Rate limit (per key) | 120 / min | BUSY |
Security posture