Guide
Generate a packing slip PDF in n8n
An order lands, and the warehouse needs a slip in the box — the SKUs, the quantities, where it’s going. This is the honest, working version: a real n8n workflow that turns an order into a branded packing slip PDF and files it to Google Drive, with the copy-paste JSON and a step-by-step walkthrough. First, the distinction that decides which document you’re actually building.
A packing slip, not an invoice
A packing slip and an invoice come off the same order and look superficially alike, so they get conflated — but they do different jobs, and pdfmill ships them as two separate templates.
- A packing slip is what’s in the box: SKUs, item descriptions, quantities, the ship-to address, the order number, and a “packed” checkbox for the picker. No prices, no tax, no amount due — it travels with the shipment so the warehouse and the customer can check the order is complete.
- An invoice is the bill: unit prices, tax, totals, payment terms. It goes to whoever pays — not into the box.
pdfmill’s Packing Slip template deliberately leaves money out — its footer even reads “This is a packing slip, not an invoice — no prices included.” If you actually want the bill, that’s the invoice guide, and this isn’t it. If you want the document that ships with the goods, read on — and no, n8n has no native packing-slip node, so you generate it, which the next section sets up.
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. There is no native PDF-generation node in n8n’s palette (the built-in Extract from File only reads an existing PDF), so a community node, a self-hosted Chrome, or a document API is how you make one.
- 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 packing-slip 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 order) → Generate PDF (Packing Slip) → Google Drive.
{
"name": "pdfmill — New order to packing slip PDF, saved to Drive",
"nodes": [
{
"parameters": {},
"id": "25-150a80db-e4dd-478c-92d4-d8cbf7b916ba",
"name": "When clicking 'Execute workflow'",
"type": "n8n-nodes-base.manualTrigger",
"typeVersion": 1,
"position": [
0,
300
]
},
{
"parameters": {
"mode": "raw",
"jsonOutput": "{\n \"orderNumber\": \"SO-2026-3187\",\n \"orderedAt\": \"2026-07-19\",\n \"shippedAt\": \"2026-07-21\",\n \"carrier\": \"DHL Express\",\n \"trackingNumber\": \"JD014600003118872291\",\n \"shipFrom\": {\n \"name\": \"Nordic Trail Supply AB\",\n \"address\": \"Industrivägen 8\\n433 61 Sävedalen, Sweden\"\n },\n \"shipTo\": {\n \"name\": \"Ana Popescu\",\n \"address\": \"Strada Aviatorilor 22, ap. 14\\n011853 Bucharest, Romania\"\n },\n \"items\": [\n {\n \"sku\": \"NTS-TENT-02\",\n \"description\": \"Alpine 2-person tent, moss green\",\n \"quantity\": 1\n },\n {\n \"sku\": \"NTS-STV-11\",\n \"description\": \"Compact gas stove with piezo ignition\",\n \"quantity\": 1\n },\n {\n \"sku\": \"NTS-BTL-07\",\n \"description\": \"Insulated steel bottle 0.75 L\",\n \"quantity\": 2\n },\n {\n \"sku\": \"NTS-SCK-03\",\n \"description\": \"Merino hiking socks, size 39-42\",\n \"quantity\": 3\n }\n ],\n \"totalItems\": 7,\n \"totalWeight\": \"4.6 kg\",\n \"notes\": \"Leave with neighbor at ap. 15 if not home. Fragile: stove contains glass ignition parts.\"\n}",
"options": {}
},
"id": "26-f6c2427f-1cb8-4d60-8d42-81a44d6949a6",
"name": "Order (sample)",
"type": "n8n-nodes-base.set",
"typeVersion": 3.4,
"position": [
220,
300
]
},
{
"parameters": {
"operation": "template",
"template": "packing-slip",
"data": "={{ $json }}",
"format": "pdf",
"binaryPropertyName": "data",
"options": {}
},
"id": "27-e0278032-ebfd-46be-8b7a-b04701db6d62",
"name": "Generate packing slip PDF",
"type": "n8n-nodes-generate-pdf.generatePdf",
"typeVersion": 1,
"position": [
440,
300
]
},
{
"parameters": {
"operation": "upload",
"inputDataFieldName": "data",
"name": "=Packing slip - {{ $json.orderNumber }}.pdf",
"driveId": {
"__rl": true,
"mode": "list",
"value": "My Drive"
},
"folderId": {
"__rl": true,
"mode": "list",
"value": "root"
},
"options": {}
},
"id": "28-6de93dc1-b58c-4f30-903a-b5115966e3dc",
"name": "Save to Google Drive",
"type": "n8n-nodes-base.googleDrive",
"typeVersion": 3,
"position": [
660,
300
]
},
{
"parameters": {
"content": "## 📦 Order → Packing Slip PDF → Drive\nOn a new order, generate a packing slip PDF and file it (or attach it to the fulfilment task).\n\n**Setup:** a **pdfmill** credential on the Generate node and a **Google Drive** credential on the save node.",
"height": 200,
"width": 560,
"color": 5
},
"id": "29-197c5571-f02b-4e0a-a640-4004593bf2ef",
"name": "Sticky Note",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
0,
40
]
},
{
"parameters": {
"content": "### In production\nReplace the manual trigger with your store’s **order webhook** (Shopify/WooCommerce/etc.) and map the order into the packing-slip fields.",
"height": 200,
"width": 300,
"color": 4
},
"id": "30-3bb652df-5040-42dd-9004-c9cc20b12a82",
"name": "Sticky Note1",
"type": "n8n-nodes-base.stickyNote",
"typeVersion": 1,
"position": [
220,
520
]
}
],
"connections": {
"When clicking 'Execute workflow'": {
"main": [
[
{
"node": "Order (sample)",
"type": "main",
"index": 0
}
]
]
},
"Order (sample)": {
"main": [
[
{
"node": "Generate packing slip PDF",
"type": "main",
"index": 0
}
]
]
},
"Generate packing slip PDF": {
"main": [
[
{
"node": "Save to Google Drive",
"type": "main",
"index": 0
}
]
]
}
},
"active": false,
"settings": {
"executionOrder": "v1"
},
"pinData": {},
"meta": {
"templateCredsSetupCompleted": false
},
"tags": [
{
"name": "pdfmill"
}
],
"versionId": "6d763b0f-b5f4-4329-8398-881c892f702a"
}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 for your store’s order trigger (last section).
- Order (sample) — a Set node holding one sample order as JSON (order number, ordered/shipped dates, carrier and tracking,
shipFrom/shipTo, and line items withsku+quantity). This stands in for the order your real trigger produces. - Generate packing slip PDF — the pdfmill node. Operation: Generate from Template; Template: Packing Slip; Data:
{{ $json }}(the incoming order); Format: PDF; Put Output File in Field:data. Out comes the slip as a binary ondata, plus a small JSON summary (pages,bytes,requestId, file name). - Save to Google Drive — a Google Drive node that uploads the
databinary, naming the filePacking slip - {{ $json.orderNumber }}.pdf. Swap Drive for an email attachment, S3, Dropbox, or Slack without touching the Generate step.
The two sticky notes in the JSON say the same thing on the canvas — one summarising the flow, one on the production swap. Add your pdfmill credential to the Generate node and a Google Drive credential to the save node, then Execute workflow — a rendered packing slip PDF lands in your Drive.
The Packing Slip template and its data shape
Generate from Template means you supply data, not layout — the built-in Packing Slip starter handles the design. The Data field defaults to {{ $json }}, which passes the whole incoming order through; to feed specific fields instead, map them with an expression. The Packing Slip template reads these fields:
- Sender —
shipFrom(name,address), the brand block at the top, andorderNumber. - Ship-to —
shipTo(name,address) — where the box is going. - Shipment —
orderedAt,shippedAt,carrier,trackingNumber. - Line items —
items[], each withsku,description,quantity(the template draws the “packed” checkbox column for you). Note there is no unit price — a packing slip omits money. - Footer —
totalItems,totalWeight, and an optionalnotesline for delivery instructions or a fragile flag.
Want a different look — your logo, colours, extra columns? Switch the operation to Generate from HTML and pass your own markup, or start from the other starters (invoice, quote, report, certificate). The templates guide covers both. One rendered document counts as one toward your plan, however many pages the slip runs to. Need an image rather than a document — a thumbnail or an inline preview? Switch Format to PNG; PDF is what you want for the slip that ships.
Filing it, or attaching it for the warehouse
Because the slip comes out as a binary on data, anything downstream that takes a binary can consume it. Point that property wherever fulfilment needs it:
- File it — Google Drive (the sample workflow), S3, or Dropbox, uploading the
databinary — one PDF per order, named by order number. - Attach it — to a Gmail / SMTP / Outlook message to the customer or your 3PL, or to the fulfilment task itself (a Trello, Asana, or ClickUp card).
- Notify — post it to a warehouse Slack or Telegram channel as a file.
Need more than one destination? Branch after the Generate node — file the slip to Drive and attach it to the pick task from the same binary.
Going to production — one slip per order
The only thing that changes for real use is the front of the workflow. Replace the manual trigger and the sample Order node with your real order source, then map its fields into the same packing-slip shape the template expects — exactly what the workflow’s “In production” sticky note says:
- Shopify — an order-created webhook (or the Shopify Trigger node) fires on every new order; map the line items and shipping address into the slip.
- WooCommerce — the WooCommerce Trigger (or a webhook) on a new or paid order, mapped the same way.
- A webhook or a Sheet / DB row — any store, OMS, or spreadsheet that emits an order. A Schedule + a query can also batch a day’s orders, one slip each.
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 auto-generate packing slips from Shopify orders in n8n?
Trigger the workflow from your store — a Shopify order webhook (or the Shopify Trigger node), a WooCommerce webhook, or any order event — then map the order into the packing-slip fields and feed it to a Generate PDF node set to the Packing Slip template with Data as {{ $json }}. The node returns the slip as a PDF binary on the "data" field, ready to save to Drive or attach to the fulfilment task. The sample workflow on this page uses a manual trigger so you can run it once; production just swaps that first node for your store’s order trigger.
Can I save the packing slip to Google Drive?
Yes — that is exactly what the sample workflow does. The Generate PDF node outputs the slip as a binary on the "data" property; a Google Drive node after it uploads that binary, naming the file "Packing slip - {{ $json.orderNumber }}.pdf". Swap Drive for S3, Dropbox, an email attachment, or a Slack upload without touching the Generate step.
How is a packing slip different from an invoice here?
A packing slip lists what is in the box — SKUs, descriptions, quantities, the ship-to address, the order number, and a "packed" checkbox — with no prices, no tax, and no totals; it travels with the shipment so the warehouse and customer can check the order is complete. An invoice is the bill: unit prices, tax, payment terms, amount due. They are separate pdfmill templates (Packing Slip vs Invoice), and the Packing Slip template deliberately omits prices. If you want the bill instead, see the invoice guide.
Does n8n have a packing slip node?
No. There is no native packing-slip or PDF-generation node in n8n’s core palette — the built-in Extract from File node only READS an existing PDF. To produce a branded packing slip you use a community node such as Generate PDF (pdfmill), self-host a headless Chrome, or call a document API. This guide uses the community node.
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 30, 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.