Guide · n8n
Generate PDF documents from n8n
Add a document step to any n8n workflow with the
n8n-nodes-docmill community node: JSON in, a finished
PDF, DOCX, or XLSX out, ready to email, upload, or archive —
no HTML wrangling inside your workflow.
What you need
- An n8n instance (n8n 1.0 or later — the node has no external runtime dependencies).
- A Docmill API key. The free tier includes 50 documents a month (watermarked), no credit card required.
Step 1 — Install the community node
Open Settings → Community Nodes
On a self-hosted n8n instance, go to Settings → Community Nodes → Install a community node.
Enter the package name
Type
n8n-nodes-docmill, tick the box acknowledging the risks of installing community nodes, and click Install.Find the node
After the install finishes, search for Docmill in the nodes panel. On n8n Cloud, community nodes become searchable once they are approved by n8n — if you don't see it there yet, use a self-hosted instance.
Step 2 — Create the Docmill credential
Add a Docmill node to a workflow and click Create new credential (or go to Credentials → Add credential → Docmill API). Two fields:
| Field | Value |
|---|---|
| API Key | Your key, e.g. dk_live_…. Get one free
via the pricing page. |
| Base URL | Leave as https://api.docmill.io
unless you run a self-hosted Docmill instance. |
n8n verifies the credential against GET /v1/usage when you save it,
so a bad key fails immediately rather than mid-workflow.
Step 3 — The node's operations
| Operation | What it does | Parameters |
|---|---|---|
| Generate Document | Renders a template with JSON data into a PDF, DOCX, or XLSX file. The file lands in a binary property on the item. | Template ID (tpl_… or a starter like
starter:invoice), Data (JSON),
Output Format (PDF / DOCX / XLSX),
Put Output File in Field (binary property name,
default data) |
| Generate Template (AI) | Describe the document in plain language; Docmill drafts a reusable template, saved to your account, and returns its ID plus sample data. | Describe the Document — e.g. "An invoice for a design studio with line items, 8% tax, EU VAT number, payment terms…" |
| List Templates | Enumerates your templates and the built-in starters
(starter:invoice, starter:quote,
starter:report, starter:certificate). |
— |
You normally run Generate Template (AI) once while building the workflow, note the template ID it returns, then use Generate Document with that ID on every execution. Every template is plain HTML underneath, so you can inspect and tweak it.
A worked example: webhook → invoice PDF → email
Three nodes: a Webhook trigger receives order data, Docmill turns it into an invoice PDF, and Gmail (or any email/storage node) sends it.
Webhook trigger
Create a Webhook node (method POST). Suppose callers send
{"client_name": "Northwind Traders", "item": "Design sprint", "price": 4800}.Docmill — Generate Document
Operation Generate Document, Template ID
starter:invoice, Output Format PDF. Switch Data (JSON) to expression mode and map the incoming fields:{ "client": { "name": "{{ $json.body.client_name }}" }, "items": [ { "description": "{{ $json.body.item }}", "quantity": 1, "unitPrice": {{ $json.body.price }} } ], "total": {{ $json.body.price }} }The node outputs
{ success: true, bytes, format }as JSON and the file itself as the binary propertydata(filenamedocument.pdf).Send it
In a Gmail / Send Email node, add an attachment and point it at the binary property
data. The same property works for Google Drive, Dropbox, S3, Slack, and any other node that accepts binary input. If you chain several Docmill nodes, give each one a distinct Put Output File in Field name.
What the node does under the hood
One authenticated POST. If you'd rather call the API from an HTTP Request node (or anywhere else), this is the entire integration:
# one POST, one invoice curl https://api.docmill.io/v1/documents \ -H "Authorization: Bearer dk_live_…" \ -H "Content-Type: application/json" \ -d '{ "template_id": "starter:invoice", "data": { "client": {"name": "Northwind Traders"}, "items": [{"description": "Design sprint", "quantity": 1, "unitPrice": 4800}], "total": 4800 }, "output": "pdf" }' --output invoice.pdf # → %PDF-1.7 …
The n8n node calls the same endpoint with ?encoding=base64 and decodes the
response into the binary property for you. Swap "output": "pdf" for
"docx" or "xlsx" to get Word or Excel files from the same template —
in the node that's just the Output Format dropdown.
Sync vs. async
The node renders synchronously: each item waits for its file. That's the right default for webhook-triggered flows and small batches.
For bulk runs (say, hundreds of invoices from a Google Sheets read), the API also has an
async mode: add ?async=1 to the documents call and you get a job ID back
immediately; poll the job until it's done. In n8n you'd use an HTTP Request node plus a Wait
node:
# enqueue curl "https://api.docmill.io/v1/documents?async=1" \ -H "Authorization: Bearer dk_live_…" \ -H "Content-Type: application/json" \ -d '{ "template_id": "starter:invoice", "data": { … }, "output": "pdf" }' # → { "job_id": "job_a1b2c3…", "status": "queued" } # poll until status is "done", then decode data_base64 curl https://api.docmill.io/v1/jobs/job_a1b2c3… \ -H "Authorization: Bearer dk_live_…" # → { "job_id": "job_a1b2c3…", "status": "done", # "content_type": "application/pdf", "data_base64": "JVBERi0…" }
Troubleshooting
| Symptom | Cause & fix |
|---|---|
401 — invalid or missing API key |
The credential's API key is wrong, revoked, or pasted with whitespace. Re-create the credential; the built-in credential test should pass before you run the workflow. |
429 — monthly quota reached |
You've used all documents on your plan for the month (50 on Free). Upgrade at docmill.io/#pricing or wait for the cycle to reset. |
422 — render error |
The data doesn't match what the template expects (missing field, wrong type). Compare your Data (JSON) against the sample data returned when the template was created, or run List Templates to check the ID. |
| "Data must be valid JSON" / JSON parse error | An expression inside Data (JSON) produced unquoted text or trailing commas.
Quote string expressions ("{{ … }}") and leave numbers bare. |
| Node missing after restart | Community nodes must be reinstalled if the n8n instance was rebuilt without a
persistent ~/.n8n volume. |
Ready to add the document step?
Free tier: 50 documents/month, watermarked. Paid plans from $19/mo for 1,000 documents.