Guide
Generate an invoice PDF in n8n
A customer pays, an order closes, a form comes in — and you need a finished, branded invoice to send. This is the honest, working version: a real n8n workflow that turns the data already in your workflow into a PDF invoice and emails it, with the copy-paste JSON and a step-by-step walkthrough. First, the distinction that trips everyone up.
Generating an invoice vs. extracting one
Search “n8n invoice pdf” and almost everything you find is about the opposite job: reading data out of an invoice someone sent you. That’s extraction — and it’s a different problem from what most people who type that query actually want.
- Extracting (reading a PDF): a supplier emails you an invoice, and Extract from File, OCR, or an AI/LLM parser node pulls the totals and line items out into structured data. The PDF already exists; you’re mining it.
- Generating (writing a PDF): you already have the data — a Stripe payment, an order row, a form submission — and you produce a new, branded invoice PDF from it. Nothing to read; you’re creating the document.
This guide is the second one. If you meant the first — parsing invoices you receive — an Extract-from-File or AI-parser workflow is what you want, and this isn’t it. If you want to produce invoices from workflow data, read on.
What you’ll need
- An n8n instance that can install community nodes (self-hosted, or n8n Cloud on a plan that allows them).
- The Generate PDF community node. In n8n: Settings → Community Nodes → Install, and enter the package name:
n8n-nodes-generate-pdfThis is a community node with n8n verification in progress — not a verified node (yet). It installs like any community package and works today; verification only adds an in-editor badge later.
- A pdfmill API credential. Create a key in the pdfmill dashboard (it looks like
pk_live_…), add a credential of type pdfmill API, paste the key, and leave Base URL ashttps://api.pdfmill.dev. Click Test for a green check.
No headless Chrome, no server — pdfmill renders the document on its side and hands the binary back to your workflow. The full click-by-click is the five-minute quickstart.
The workflow, end to end
Here’s a complete, working invoice workflow. Copy it, and in n8n paste it straight onto the canvas (or Workflows → Import from File). It’s four nodes: manual trigger → Set (sample invoice data) → Generate PDF (Invoice) → Gmail.
{
"name": "pdfmill — Payment to invoice PDF, emailed",
"nodes": [
{
"parameters": {},
"id": "00-c5f7c4fa-5264-42d6-922c-839963fd6588",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
300
]
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "{\n \"invoiceNumber\": \"INV-2026-0042\",\n \"issuedAt\": \"2026-07-15\",\n \"dueAt\": \"2026-08-14\",\n \"paymentTerms\": \"Net 30\",\n \"currency\": \"USD\",\n \"from\": {\n \"name\": \"Fieldstone Automation LLC\",\n \"address\": \"2211 Alder Street, Suite 4\\nPortland, OR 97205, USA\",\n \"email\": \"billing@fieldstone-automation.com\",\n \"taxId\": \"US 84-2210417\"\n },\n \"billTo\": {\n \"name\": \"Harbor & Lane Coffee Roasters\",\n \"address\": \"18 Dockside Avenue\\nSeattle, WA 98101, USA\",\n \"email\": \"accounts@harborandlane.com\"\n },\n \"items\": [\n {\n \"description\": \"n8n workflow build — order-to-invoice automation (discovery, build, handover)\",\n \"quantity\": 1,\n \"unitPrice\": 2400,\n \"lineTotal\": 2400\n },\n {\n \"description\": \"Custom PDF template design (invoice + packing slip, brand-matched)\",\n \"quantity\": 2,\n \"unitPrice\": 350,\n \"lineTotal\": 700\n },\n {\n \"description\": \"Monthly automation support retainer — July 2026\",\n \"quantity\": 1,\n \"unitPrice\": 480,\n \"lineTotal\": 480\n }\n ],\n \"subtotal\": 3580,\n \"taxRate\": 8.5,\n \"taxAmount\": 304.3,\n \"total\": 3884.3,\n \"notes\": \"Payment by ACH to the account on file. Please reference INV-2026-0042. Thank you for your business.\"\n}",
"options": {}
},
"id": "01-64cedda2-0ba7-4045-ae9b-10d107964a2f",
"name": "Invoice data (sample)",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
220,
300
]
},
{
"parameters": {
"operation": "template",
"template": "invoice",
"data": "={{ $json }}",
"format": "pdf",
"binaryPropertyName": "data",
"options": {}
},
"id": "02-fceb10ac-a2d1-4004-935d-79920c953a81",
"name": "Generate invoice PDF",
"type": "n8n-nodes-generate-pdf.generatePdf",
"typeVersion": 1,
"position": [
440,
300
]
},
{
"parameters": {
"sendTo": "={{ $json.billTo.email }}",
"subject": "=Invoice {{ $json.invoiceNumber }}",
"message": "=Hi {{ $json.billTo.name }},\n\nPlease find invoice {{ $json.invoiceNumber }} attached ({{ $json.total }} {{ $json.currency }} due {{ $json.dueAt }}).\n\nThank you!",
"options": {
"attachmentsUi": {
"attachmentsBinary": [
{
"property": "data"
}
]
}
}
},
"id": "03-716c3198-3eea-4187-8219-6bd46bd8781d",
"name": "Email the invoice",
"type": "n8n-nodes-base.gmail",
"typeVersion": 2.1,
"position": [
660,
300
]
},
{
"parameters": {
"content": "## 💳 Payment → Invoice PDF → Email\nWhen a customer pays, generate a branded PDF invoice and email it — no Chrome to host.\n\n**Setup:** add a **pdfmill** credential to the Generate node, and a **Gmail** (or SMTP) credential to the email node.",
"height": 200,
"width": 560,
"color": 5
},
"id": "04-3ca9cd57-7cab-416f-8dd0-3d8f80913c03",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
0,
40
]
},
{
"parameters": {
"content": "### In production\nSwap the manual trigger for a **Stripe Trigger** (event `checkout.session.completed`) or a webhook, then map the payment fields into the invoice data.",
"height": 200,
"width": 300,
"color": 4
},
"id": "05-0f95e274-a43e-470e-84a8-87f6c5cb3299",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
220,
520
]
},
{
"parameters": {
"content": "### The document\nThe PDF comes out on the **`data`** binary property and is attached to the email. Switch **Format** to PNG for an image instead.",
"height": 200,
"width": 300,
"color": 4
},
"id": "06-c8d683bc-24f9-44b2-adc5-d4c1f3001918",
"name": "Sticky Note2",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
440,
520
]
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Invoice data (sample)",
"type": "main",
"index": 0
}
]
]
},
"Invoice data (sample)": {
"main": [
[
{
"node": "Generate invoice PDF",
"type": "main",
"index": 0
}
]
]
},
"Generate invoice PDF": {
"main": [
[
{
"node": "Email the invoice",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": false
},
"tags": [
{
"name": "pdfmill"
}
],
"versionId": "0c1d8e7c-6a84-466f-a1da-b32c7f25baf7"
}Walking it left to right:
- When clicking ‘Execute workflow’ — a manual trigger, so you can run it once and see a real PDF. In production you swap this out (last section).
- Invoice data (sample) — a Set node holding a sample invoice as JSON (invoice number, dates,
from/billTo, line items, totals). This stands in for the data your real trigger produces. - Generate invoice PDF — the pdfmill node. Operation: Generate from Template; Template: Invoice; Data:
{{ $json }}(the incoming item); Format: PDF; Put Output File in Field:data. Out comes the invoice as a binary ondata, plus a small JSON summary (pages,bytes,requestId, file name). - Email the invoice — a Gmail node that sends to
{{ $json.billTo.email }}, titles the mailInvoice {{ $json.invoiceNumber }}, and attaches thedatabinary. Swap Gmail for SMTP, Outlook, Google Drive, S3, or Slack without touching the Generate step.
The sticky notes in the JSON say the same thing on the canvas. Add your pdfmill credential to the Generate node and a Gmail credential to the email node, then Execute workflow — you get a rendered invoice PDF in the email.
The Invoice template and its data shape
Generate from Template means you supply data, not layout — the built-in Invoice starter handles the design. The Data field defaults to {{ $json }}, which passes the whole incoming item through; to feed specific fields instead, map them with an expression. The Invoice template reads these fields:
- Header —
invoiceNumber,issuedAt,dueAt,paymentTerms,currency. - Parties —
from(name,address,email,taxId) andbillTo(name,address,email). - Line items —
items[], each withdescription,quantity,unitPrice,lineTotal. - Totals —
subtotal,taxRate,taxAmount,total, and an optionalnotesline.
Want a different look — your logo, colours, extra fields? Switch the operation to Generate from HTML and pass your own markup, or start from the other starters (invoice, quote, report, certificate, packing slip). The templates guide covers both. One rendered document counts as one toward your plan, however many pages the invoice runs to.
PDF or PNG?
The Format field takes PDF or PNG — same node, same data.
- PDF for the invoice itself: multi-page, selectable text, the format customers and accounting systems expect, and the right thing to attach or archive. This is the default, and what you want here.
- PNG when you need an image rather than a document — a thumbnail, an inline preview in an app, or a social/share card. It’s a flat image, so use it for display, not for the sendable invoice.
Emailing or storing the result
Because the invoice comes out as a binary on data, anything downstream that takes a binary can consume it. Point that property at whichever node you need:
- Email it — Gmail / SMTP / Outlook, with
dataas the attachment (the sample workflow does this). - Store it — Google Drive, S3, or Dropbox, uploading the
databinary. - Notify — post it to Slack or Telegram as a file.
Going to production
The only thing that changes for real use is the front of the workflow. Replace the manual trigger and the sample Set node with your real source, then map its fields into the same invoice shape the template expects:
- Stripe Trigger on
checkout.session.completed— invoice on every payment. Map the customer, amount, and line items into the invoice fields. - Webhook / order event from your store or app — invoice when an order is placed or marked paid.
- Schedule + a query (Postgres, Google Sheets) — batch monthly or weekly invoices.
pdfmill is flat-priced: a permanent Free tier of 75 documents a month (no card), then $9/500, $19/2,000, and $49/10,000 per month. The plan is a hard cap — at the limit the node returns a clear QUOTA_EXCEEDED (402) with an upgrade prompt, never a silent overage or a surprise invoice of its own. Current numbers are on the pricing page. Still weighing options? See how to generate PDFs in n8n and the best PDF API for n8n.
FAQ
How do I generate an invoice PDF in n8n?
Install the community node n8n-nodes-generate-pdf, add a pdfmill API credential, then drop a Generate PDF node into your workflow. Choose the Invoice template, leave Data as {{ $json }} so it uses the incoming item, and run. The node returns the finished invoice as a binary on the output field (default "data"), ready to email or store.
Does n8n have a native PDF node?
Not for generation. n8n’s built-in Extract from File node only READS an existing PDF (pulling text or data out of it); nothing in the core palette turns your data into a new PDF. To generate one you use a community node such as Generate PDF (pdfmill), self-host a headless Chrome, or call a document API.
What is the difference between generating and extracting an invoice in n8n?
Extracting reads fields out of an invoice you received — Extract from File, OCR, or an AI parser turn a supplier’s PDF into structured data. Generating is the reverse: you already have the data (a payment, an order, a form) and produce a new branded invoice PDF. This guide is about generating.
Can I email the invoice automatically?
Yes. The Generate PDF node outputs the invoice as a binary on the "data" property. Add a Gmail, SMTP, or Outlook node after it and attach that binary — the sample workflow on this page emails the invoice to {{ $json.billTo.email }} with the invoice number in the subject.
Should the invoice be a PDF or a PNG?
PDF for an invoice you send or archive — it is multi-page, has selectable text, and is the format finance systems and customers expect. PNG is for a preview, thumbnail, or an image you embed somewhere. Same node and same data; you just switch the Format field.
Is the pdfmill n8n node verified?
It is a community node (n8n-nodes-generate-pdf) with n8n verification in progress — not yet verified. You install it via Settings → Community Nodes like any community package. Everything in this guide works today; verification only adds an in-editor badge and a listing on n8n.io.
The workflow above is the real gallery template that ships with the node — checked July 28, 2026. Options and prices change; this guide links the pricing and comparison pages rather than repeating numbers that go stale here.
See for yourself
Render your first PDF from an n8n workflow in about five minutes — the Free plan is 75 documents a month, no card required.