n8n
PaperPony turns HTML into PDFs. The node does it inside a workflow: one step fills a saved template or takes markup you supply, and the finished file arrives attached to the item, so the next step can email it or drop it in a folder.
You need a key, and it costs nothing
Type an email address, follow the link that arrives, and create a key. That is the whole of it: no card, nobody to wait for, and about a minute. If you have never used PaperPony before, the same step makes the account. The free plan renders 100 pages a month and stops there rather than billing you.
Or try the engine first. The invoice generator needs no key and no account at all, and it runs the same renderer, so what it produces is what the node will hand back.
Install the node
In your n8n, open Settings, then Community nodes, and install this package by name:
n8n-nodes-paperponyn8n Cloud lists verified nodes only. If you cannot find the install button at all, you are on Cloud and this package is not there yet; on self-hosted n8n the button is where the steps above say.
The package has no dependencies of its own. That is a condition of n8n’s verification rather than a preference, and it means the node restates the shapes the API sends instead of importing them from our SDK.
Connect your account
Create a PaperPony credential and paste your key into it. Leave Base URL alone. Save, and n8n tests the credential straight away.
If you do not have a key yet, this is the moment to get one, and it does not interrupt what you are doing: type an email address and follow the link that arrives. The sign-in page makes the account if you have never used PaperPony before, so there is nothing to sign up for separately.
The test calls GET /v1/account, which needs the key. It could have called the health endpoint, and that would have been worse: health is unauthenticated, so it answers 200 for a key that is blank, wrong or revoked, and a test that passes with no credential teaches you to believe it.
What the node does
Three actions. Create a PDF from a template fills one of your saved templates, and the template list loads from your account, so you pick it by name. Create a PDF from HTML takes markup you supply. Get a job looks up a PDF made earlier by its job ID, and waits if it is still being drawn.
Return the File is on by default, so the PDF arrives as binary data on the item rather than as a link you have to fetch. Turn it off when nothing downstream needs the file and a link is enough.
There is no trigger, and there will not be one. The API has no webhooks and no events worth subscribing to, so a PaperPony trigger would have to invent something to fire on.
Fill in the values
Fill in Fields gives you a row per value: the name on the left has to match what the template asks for, and the value on the right can be dragged in from an earlier step. That covers a letter or an invoice header.
It cannot cover a list. Invoice lines are not name and value pairs, so switch Values to Use JSON and map a whole object instead.
{
"invoice_number": "INV-2041",
"client": "Northwind Trading Ltd",
"amount": "1250",
"items": [
{ "description": "Design work", "amount": "800" },
{ "description": "Hosting, August", "amount": "450" }
]
}Amounts go in as plain numbers. 1250 or "1250" both work, and the template decides how they are printed. Currency symbols, thousands separators and words belong in the template, not in the value.
Use it with an AI agent
The node can be a tool. Add an AI Agent, click the plus under its Tool connector, and search for PaperPony: n8n offers PaperPony Tool, which is this node with its inputs removed and the agent attached instead. A Basic LLM Chain has no Tool connector at all, so if there is nowhere to attach it, that is why.
Decide field by field who fills what. Pin the template and the document number yourself, and hand the agent the values that come out of the conversation. Names are always yours: the agent should never be inventing the key a template reads.
Give the agent a number when you want a number. Asked for an amount in plain language, a model writes 480 euros, the currency helper gets something that is not a finite number, and the render is refused. Setting the type in the expression is what stops it:
{{ $fromAI('amount', 'Amount as a plain number, no currency symbol or words, for example 480', 'number') }}When a render is refused
A failed step names the field that was wrong and carries the API’s own error code with it. Two are worth recognising on sight. invalid_request means the document or its values were rejected, and the message says which part. insufficient_credits means the account is out for this period, and nothing about the workflow will fix it.
Turn on n8n’s own Continue On Fail and a refused item hands back the job row as well as the message, so a run over fifty invoices carries on past the one whose data was wrong instead of losing the other forty-nine.
Every code is listed on the errors page.
Writing the template
Templates are HTML with Handlebars in them. The template guide covers the helpers, page breaks and fonts, and the recipes are whole documents you can store as they are.