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

Step 1 — Install the community node

  1. Open Settings → Community Nodes

    On a self-hosted n8n instance, go to Settings → Community Nodes → Install a community node.

  2. Enter the package name

    Type n8n-nodes-docmill, tick the box acknowledging the risks of installing community nodes, and click Install.

  3. 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:

FieldValue
API KeyYour key, e.g. dk_live_…. Get one free via the pricing page.
Base URLLeave 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

OperationWhat it doesParameters
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.

  1. Webhook trigger

    Create a Webhook node (method POST). Suppose callers send {"client_name": "Northwind Traders", "item": "Design sprint", "price": 4800}.

  2. 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 property data (filename document.pdf).

  3. 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…" }
Async bulk jobs are included from the Growth plan up. Each generated file meters as one document either way — no multipliers.

Troubleshooting

SymptomCause & 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.

Start free API docs

More guides

Generate PDFs from Zapier

The Generate Document action, field mapping, and a worked Zap.

Generate PDFs from Make

The Docmill app's modules and a worked scenario with binary output.

EU e-invoicing: the readable invoice

Pairing structured XML with a human-readable PDF in one flow.