n8n Integration: Automate Document Generation
Last updated March 23, 2026
The PDFMonkey n8n node lets you generate, retrieve, download, and delete documents directly from your n8n workflows. If you are setting up PDFMonkey with n8n for the first time, start with the Getting Started section below.
Getting Started
n8n is a workflow automation platform that connects different apps and services together. It is an open-source alternative to tools like Zapier and Make, offering both cloud and self-hosted options.
Before you begin, make sure you have:
- A PDFMonkey account (sign up here)
- An n8n account or instance (sign up at n8n.io or self-host)
- Your PDFMonkey API key
- A published template in PDFMonkey
For the full account creation and template setup walkthrough, see From Zero to First Document.
Setting Up Credentials
Before using the PDFMonkey node, you need to configure your API credentials:
- In your n8n workflow, add a PDFMonkey node
- Click on Create New Credentials
- Enter your PDFMonkey API key (found in your PDFMonkey dashboard)
- Click Save
Where to find your API key
Your First Workflow
Let’s create a simple workflow that generates a document when triggered manually. Use the template you created in From Zero to First Document, or create a simple template with a greeting variable.
Step 1: Add a Manual Trigger
- Create a new workflow in n8n
- The Manual Trigger node should already be there
- This allows you to test your workflow manually
Step 2: Add the PDFMonkey Node
- Click the + button to add a new node
- Search for PDFMonkey
- Select the PDFMonkey node
- Choose Generate Document as the operation
Step 3: Configure the Generate Document Operation
In the PDFMonkey node configuration:
- Select your PDFMonkey credentials (or create them if you haven’t)
- Set your Template ID from your PDFMonkey template
- Set the Payload Input Method to Key-Value Pairs
- Add the following fields:
- Key:
name→ Value:Peter Parker - Key:
favoriteNumber→ Value:8
- Key:
Payload methods
Variable naming
Step 4: Test Your Workflow
- Click on Execute Workflow (the play button at the bottom)
- Wait a few seconds for the document to generate
- You should see the document details in the output
- The file is now available at the
download_urlprovided
Step 5: Download the File (Optional)
If you want to download the generated file as binary data in n8n:
- Enable Download File in the PDFMonkey node options
- The file is available as binary data in the next nodes
Example: Webhook to Document to Email
Let’s create a more practical workflow that:
- Receives data from a webhook
- Generates a document with PDFMonkey
- Sends the document by email
The Workflow Structure
- Webhook node: receives form data
- PDFMonkey node: generates the document
- Send Email node: sends the file as attachment
Configuration
Webhook node:
- Set to POST method
- Path:
/generate-document
PDFMonkey node:
- Operation: Generate Document
- Select your template
- Map webhook data to template variables:
name→{{ $json.name }}favoriteNumber→{{ $json.favoriteNumber }}
- Enable Download File option
Send Email node:
- Use Gmail, SendGrid, or any SMTP service
- In attachments, reference the PDFMonkey binary data:
- Property Name:
data - File Name:
document.pdf
- Property Name:
Testing webhooks
Use the Test URL provided by n8n to send POST requests with JSON data like:
{
"name": "John Doe",
"favoriteNumber": 42
}
You’ve successfully set up your first PDFMonkey workflow in n8n.
Generate a Document
The Generate Document operation creates a document from one of your PDFMonkey templates. You provide a template and a dynamic data payload, and PDFMonkey renders the file.
Payload Input Methods
The PDFMonkey node offers two ways to send data to your template.
Key-Value Pairs (Simple Mode) is the easiest way to send simple data structures. You add fields one by one, each with a key (the variable name in your template) and a value (static or dynamic from previous nodes).
JSON Format (Advanced Mode) handles complex data structures, nested objects, or arrays. Use JSON when your template expects structured data:
{
"customer": {
"name": "Acme Inc.",
"email": "contact@acme.com",
"address": {
"street": "123 Main St",
"city": "New York",
"zip": "10001"
}
},
"items": [
{
"product": "Widget",
"quantity": 5,
"price": 10.99
},
{
"product": "Gadget",
"quantity": 2,
"price": 24.99
}
],
"total": 104.93
}
In your template, access nested data with dot notation:
<h2>Invoice for {{customer.name}}</h2>
<p>{{customer.address.street}}, {{customer.address.city}}</p>
{% for item in items %}
<p>{{item.product}} x{{item.quantity}} = {{item.price}}</p>
{% endfor %}
For more on structuring your dynamic data, see Defining Dynamic Data.
Using Expressions
n8n expressions let you reference data from previous nodes dynamically:
{{ $json.customerName }} // Simple field
{{ $node["Webhook"].json["email"] }} // From specific node
{{ $json.items.length }} // Array length
{{ new Date().toISOString() }} // Current date
You can use expressions in Key-Value pair values, JSON payloads (as string values), the custom filename field, and metadata fields.
Custom Filename
You can specify a custom name for the generated file. This is useful when storing files in Google Drive, Dropbox, or other storage services.
In the PDFMonkey node options:
- Expand Additional Options
- Set Custom Filename
- Use a static name or n8n expressions:
Invoice-{{ $json.invoiceNumber }}.pdf
Report-{{ $now.format('YYYY-MM-DD') }}.pdf
{{ $json.customerName }}-Contract.pdf
Filename restrictions
- Do not use slashes
/or backslashes\ - Avoid special characters that might cause issues on different operating systems
- Non-latin characters may be escaped or replaced
For more details on filename options, see Custom Filename.
Metadata
Metadata is additional information attached to a document that does not appear in the generated file itself. It is useful for tracking document origin, storing reference IDs, and filtering in webhooks.
To add metadata:
- Expand Additional Options in the PDFMonkey node
- Set Metadata to Key-Value Pairs or JSON
- Add your metadata fields:
{
"orderId": "ORD-12345",
"customerEmail": "john@example.com",
"environment": "production"
}
You can retrieve metadata later using the Get Document operation or in webhook triggers.
Metadata vs Payload
- Payload (dynamic data): Data used to render the document content
- Metadata: Information attached to the document but not visible in the output; included in webhook notifications
Wait for Document
By default, the Generate Document operation waits for the document to be fully generated before continuing.
Document generation time
If you need to disable waiting and handle completion asynchronously, you can use the PDFMonkey Trigger or poll for completion instead.
Arrays and Complex Data
n8n makes it easy to work with arrays from previous nodes. Here is an example using Google Sheets data.
Google Sheets node output:
[
{ "product": "Widget", "qty": 5, "price": 10 },
{ "product": "Gadget", "qty": 2, "price": 25 }
]
In PDFMonkey node (JSON mode):
{
"customerName": "{{ $json.customerName }}",
"items": {{ $node["Google Sheets"].json }}
}
The array is passed directly to your template where you can loop over it:
{% for item in items %}
<tr>
<td>{{item.product}}</td>
<td>{{item.qty}}</td>
<td>{{item.price}}</td>
</tr>
{% endfor %}
For more on loops and conditional rendering, see Conditions and Loops.
Handling Multiple Items
If your workflow processes multiple items (like multiple customers or orders), use n8n’s Split In Batches node:
1. Get Data (returns 100 items)
2. Split In Batches (batch size: 1)
3. PDFMonkey - Generate Document (runs 100 times)
4. Store files
Or use the Loop Over Items node for more control.
Rate limits
Error Handling
Use n8n’s error handling features to manage failures:
- Click on the PDFMonkey node
- Go to Settings tab
- Configure On Error:
- Stop Workflow (default)
- Continue With Last Successful Item
- Continue Execution
For more robust error handling, add an IF node after PDFMonkey to check the document status:
IF: {{ $json.status }} equals "success"
-> TRUE: Continue with the file
-> FALSE: Send error notification
PDFMonkey Trigger
The PDFMonkey Trigger is a webhook-based trigger that listens for document generation events. When a document finishes generating, PDFMonkey sends a notification to your n8n workflow. This is useful for automating post-generation actions like storing files, sending notifications, or updating databases.
For background on how PDFMonkey webhooks work (including event types, payload format, and signature verification), see Webhooks.
Setup
- In your n8n workflow, click + to add a new node
- Search for PDFMonkey Trigger and select it as your workflow’s starting point
- Select your PDFMonkey API credentials
- Choose which templates to listen to:
- Any Template: trigger for all documents in your workspace
- Specific Template: trigger for a single template
- Multiple Templates: trigger for several selected templates
- Copy the Webhook URL displayed by the trigger node
- In your PDFMonkey dashboard, go to the Webhooks section
- Create a new endpoint with the n8n webhook URL
- Check the success and failure events, then press Create
- Back in n8n, click the Activate toggle to enable your workflow
Production vs Test webhooks
n8n provides two URLs:
- Test URL: For testing in the n8n editor
- Production URL: For activated/published workflows
Make sure to update your PDFMonkey webhook URL when activating your workflow.
Trigger Data
When a document finishes generating, the trigger receives a DocumentCard object. This includes document metadata, status, and download URL, but does not include the original dynamic data you sent:
{
"document": {
"id": "a5e86d72-f5b7-43d4-a04e-8b7e08e6741c",
"app_id": "d6b4e8f2-7a3c-4d1e-9f5b-2c8a1d3e6f90",
"created_at": "2050-03-13T12:34:56.181+02:00",
"document_template_id": "2903f5b4-623b-4e10-b2e3-dc7e2e67ea39",
"document_template_identifier": "My Invoice Template",
"download_url": "https://pdfmonkey.s3.eu-west-1.amazonaws.com/...",
"failure_cause": null,
"filename": "2050-03-14 Peter Parker.pdf",
"meta": {
"_filename": "2050-03-14 Peter Parker.pdf",
"clientRef": "spidey-616"
},
"output_type": "pdf",
"preview_url": "https://preview.pdfmonkey.io/...",
"public_share_link": null,
"status": "success",
"updated_at": "2050-03-13T12:34:59.412+02:00"
}
}
Dynamic data is not included
Auto-Download
The PDFMonkey Trigger has a Download File option that automatically downloads the generated file when the trigger fires.
When enabled:
- The file is downloaded as binary data
- It is available immediately in the next nodes
- No need for a separate Download File operation
To enable it:
- Open the trigger node settings
- Expand Additional Options
- Toggle Download File to ON
The binary data is available with the key data.
Use Cases
Store files in Google Drive:
1. PDFMonkey Trigger (Download File: enabled)
2. Google Drive - Upload File
- File: {{ $binary.data }}
- Folder: /Invoices/
- Filename: {{ $json.filename }}
Send notification to Slack:
1. PDFMonkey Trigger
2. Slack - Send Message
- Channel: #notifications
- Message: "New document generated: {{ $json.filename }}"
- Attachment: {{ $json.download_url }}
Update database record:
1. PDFMonkey Trigger
2. Postgres - Update
- Table: orders
- Where: id = {{ $json.metadata.orderId }}
- Set: pdf_url = {{ $json.download_url }}, status = 'completed'
Email document to customer:
1. PDFMonkey Trigger (Download File: enabled)
2. Gmail - Send Email
- To: {{ $json.metadata.customerEmail }}
- Subject: Your invoice is ready
- Attachments: {{ $binary.data }}
Metadata for Routing
Metadata enables conditional workflows. When generating a document, attach routing information:
{
"metadata": {
"documentType": "invoice",
"customerId": "12345",
"sendEmail": true
}
}
Then in your triggered workflow, use an IF node or Switch node to route based on metadata:
1. PDFMonkey Trigger
2. Switch node
- Case 1: {{ $json.metadata.documentType }} = "invoice" -> Store in accounting
- Case 2: {{ $json.metadata.documentType }} = "report" -> Share on Slack
- Case 3: {{ $json.metadata.documentType }} = "contract" -> Store in DocuSign
Testing
Method 1: Generate a test document. Use another workflow or the API to generate a document, wait for the webhook to fire, and check the trigger node execution in n8n.
Method 2: Use the test webhook.
- Click Listen for event in the trigger node
- Generate a document from your PDFMonkey template
- The trigger catches the event and displays the data
- Click Use test event to use this data while building your workflow
Trigger from the dashboard
You can also have multiple n8n workflows listening to the same template. Each webhook receives the notification independently, which is useful for separating environments or having different workflows for different document types.
Delivery Guarantees
PDFMonkey uses Svix to deliver webhooks. Deliveries follow these guarantees:
- At-least-once delivery: You might receive the same event multiple times
- Best-effort ordering: Events are usually in order but not guaranteed
- Automatic retries: Failed deliveries are retried with exponential backoff
- Signature verification: Every webhook is signed so you can verify authenticity
Make your workflow idempotent
For full details on webhook configuration (including channel routing and signature verification), see Webhooks.
Other Operations
Beyond generating documents and reacting to triggers, the PDFMonkey node supports several operations for managing documents.
Get Document
The Get Document operation retrieves information about a previously generated document. Use it to check a document’s status, retrieve its download URL, access attached metadata, or verify a document exists before processing.
Required field: Document ID
Document ID: {{ $json.documentId }}
The operation returns complete document information including status, download URL, preview URL, metadata, and timestamps.
Document status values:
draft— document is created but not yet queued for generationpending— document is queued for generationgenerating— document is currently being renderedsuccess— document generated successfullyfailure— generation failed (checkfailure_causefor details)
For the full status lifecycle, see Document Statuses.
Download File
The Download File operation downloads a generated file as binary data. Use it to download a file that was generated earlier, get binary data separately from generation, or re-download a document for processing.
Required field: Document ID
Optional field: Binary Property Name (default: data)
Document ID: {{ $json.documentId }}
Binary Property Name: pdfFile
The file is stored as binary data and can be used in email attachments, file storage nodes (Google Drive, Dropbox, etc.), FTP uploads, or further processing nodes.
Generate Document has built-in download
Delete Document
The Delete Document operation permanently removes a document from PDFMonkey. Use it to clean up after sending a document, remove documents containing sensitive data, manage storage quotas, or implement document retention policies.
Required field: Document ID
Document ID: {{ $json.documentId }}
Deletion is permanent
TTL as alternative
Polling for Completion
If you generated a document with Wait for Document disabled, you can poll for its completion instead of using a webhook trigger:
1. PDFMonkey - Generate Document (Wait: disabled)
2. Wait (10 seconds)
3. PDFMonkey - Get Document
- Document ID: {{ $node["PDFMonkey"].json.id }}
4. IF node
- {{ $json.status }} = "success"
- TRUE: Continue with the file
- FALSE: Loop back to step 2
Better approach: Use the trigger
Combining Operations
Generate, store, and clean up:
1. Manual Trigger
2. PDFMonkey - Generate Document (Download: enabled)
3. Google Drive - Upload File
- File: {{ $binary.data }}
- Folder: /Invoices/
4. Postgres - Insert
- Table: documents
- Data: {
drive_url: {{ $node["Google Drive"].json.webViewLink }},
pdfmonkey_id: {{ $node["PDFMonkey"].json.id }}
}
5. PDFMonkey - Delete Document
- Document ID: {{ $node["PDFMonkey"].json.id }}
Conditional download based on status:
1. Webhook (receives document ID)
2. PDFMonkey - Get Document
- Document ID: {{ $json.documentId }}
3. IF node
- Condition: {{ $json.status }} = "success"
- TRUE:
4a. PDFMonkey - Download File
5a. Send to customer
- FALSE:
4b. Send error notification
5b. PDFMonkey - Delete Document (cleanup failed attempt)
Re-generate and replace:
1. Webhook (receives order update)
2. PDFMonkey - Delete Document
- Document ID: {{ $json.oldDocumentId }}
3. PDFMonkey - Generate Document
- Template: Invoice
- Payload: {{ $json.updatedData }}
4. Update database with new document ID
Troubleshooting
Authentication Errors
Invalid API key:
401 Unauthorized - Invalid API key
- Go to your PDFMonkey dashboard
- Navigate to Account then API
- Copy your API key
- In n8n, update your PDFMonkey credentials with the correct key
- Test the connection
For more on API authentication, see Authentication.
Multiple workspaces
If your credentials suddenly stop working, delete the old credentials in n8n, create new ones with a fresh API key, and update all nodes using those credentials.
Template Not Found
404 Not Found - Template does not exist
Causes: the template was deleted, the wrong workspace or API key is in use, or the template ID is incorrect.
Solution: Verify the template exists in your PDFMonkey dashboard, check you are using the correct API key, and re-select the template from the dropdown in n8n.
Template not published:
422 Unprocessable Entity - Template is not published
Go to your template in PDFMonkey and make sure it is published by clicking the Publish button, then try generating again.
Common mistake
Invalid Payload
422 Unprocessable Entity - Invalid payload
Causes: invalid JSON syntax (when using JSON mode), wrong data types, or missing required fields.
Common JSON syntax issues:
Missing quotes:
// Wrong
{ name: "John" }
// Correct
{ "name": "John" }
Trailing commas:
// Wrong
{
"name": "John",
"age": 30,
}
// Correct
{
"name": "John",
"age": 30
}
Unescaped double quotes in values:
// Wrong - nested quotes break the JSON
{ "name": "Peter "Spider-Man" Parker" }
// Correct - escape inner quotes with backslash
{ "name": "Peter \"Spider-Man\" Parker" }
Using n8n expressions in JSON:
When using expressions, make sure to stringify objects:
// Wrong - Will create invalid JSON
{
"items": {{ $json.items }}
}
// Correct - Properly stringify
{
"items": {{ JSON.stringify($json.items) }}
}
Use Key-Value Pairs mode
Download Errors
Download URL expired:
403 Forbidden - Download URL has expired
Download URLs expire after 1 hour for security reasons.
Option 1: Use Get Document to get a fresh URL, then download from the new URL with an HTTP Request node.
Option 2: Enable the Download File option in the Generate Document node to download immediately after generation.
Option 3: Store the binary data in a file storage service (Google Drive, S3, etc.) instead of relying on PDFMonkey URLs.
For more details, see Download URL Returns 403.
Binary data not available:
If no binary data is available for attachment or storage, make sure Download File is enabled:
- In Generate Document operation: Additional Options then Download File
- In PDFMonkey Trigger: Additional Options then Download File
- Or use a Download File operation explicitly
Webhook Issues
Webhook not receiving events checklist:
- Workflow is activated (not just saved)
- Webhook URL is correct in PDFMonkey
- Using Production URL not Test URL
- Template is published
- Firewall is not blocking requests
To debug: check the Executions tab in n8n for errors, go to template settings in the PDFMonkey dashboard and check webhook delivery logs, and try generating a test document manually. See Webhooks for webhook configuration details.
Receiving duplicate webhook events is expected behavior. PDFMonkey webhooks use at-least-once delivery. Make your workflow idempotent by checking if you have already processed a document:
1. PDFMonkey Trigger
2. Postgres - Check if document ID exists
3. IF node
- Already processed: Stop
- New document: Continue processing
Wrong webhook URL: After activating your workflow, the webhook URL changes from Test to Production. Copy the Production URL from the trigger node and update the webhook URL in your PDFMonkey settings.
Expression Errors
Cannot read property of undefined:
Cannot read property 'field' of undefined
This happens when trying to access data that does not exist from a previous node.
Check the node name:
// Wrong node name
{{ $node["PDFmonkey"].json.id }}
// Correct node name (capital M)
{{ $node["PDFMonkey"].json.id }}
Check the data exists:
// Assumes field exists
{{ $json.customer.email }}
// Use optional chaining (n8n 1.0+)
{{ $json.customer?.email }}
// Or provide default value
{{ $json.customer?.email || 'no-email@example.com' }}
Use the expression editor in n8n (click the Expression button) and use the autocomplete to ensure you are referencing the correct fields.
Workflow Timeout
Workflow execution timed out
Causes: document taking too long to generate, network issues, or large file downloads.
Option 1: Increase the timeout in workflow settings (Execution Timeout).
Option 2: Disable “Wait for Document” and use a webhook trigger in a separate workflow.
Option 3: Split into multiple workflows and use webhooks to chain them together.
Memory Errors
JavaScript heap out of memory
This happens when processing very large files or data in n8n.
Solutions:
- Process items in smaller batches (use the Split In Batches node)
- Use streaming where possible
- Increase n8n memory allocation (self-hosted only)
- Store large files externally instead of passing them through the workflow
Rate Limiting
429 Too Many Requests - Rate limit exceeded
Add Wait nodes between operations when processing multiple documents:
1. Get items to process
2. Split In Batches (size: 10)
3. Wait (5 seconds)
4. PDFMonkey - Generate Document
5. Loop
Or use the Code node to add delays:
// Wait 1 second per item
await new Promise(resolve => setTimeout(resolve, 1000));
return items;
JSON Formatting
Line breaks in JSON: JSON does not support raw line breaks in strings:
// Wrong
{
"description": "Line 1
Line 2"
}
// Correct
{
"description": "Line 1\nLine 2"
}
Or use a Code node to escape:
items[0].json.description = items[0].json.description.replace(/\n/g, '\\n');
return items;
Special characters: Escape double quotes inside string values:
// Wrong - unescaped quotes break JSON
{ "html": "<div class=\"test\">Hello</div>" }
// Correct - escaped inner quotes
{ "html": "<div class=\"test\">Hello</div>" }
Or use Key-Value Pairs mode which handles escaping automatically.
Next Steps
- From Zero to First Document: Set up your PDFMonkey account and create your first template
- Defining Dynamic Data: Learn how to structure the JSON payload for your templates
- Custom Filename: Control the name of generated files
- Document Statuses: Understand the lifecycle of a generated document
- Webhooks: Receive real-time notifications when documents finish generating
- Download URL: How temporary download links work and how to refresh them
- Retention and Deletion: Set up automatic document cleanup with TTL
- Explore other integrations: Zapier, Make, Workato
Need More Help?
If you are still experiencing issues:
- n8n documentation: docs.n8n.io
- PDFMonkey status: status.pdfmonkey.io
- n8n Community: community.n8n.io
- PDFMonkey support: support@pdfmonkey.io
Include details in support requests