Generate invoice PDFs in Node.js
The simplest way to generate invoice PDFs in Node.js is to POST an invoice template and your billing JSON to the Docweave API with the built-in fetch — no headless browser to install, launch, or keep patched yourself.
An invoice template with placeholders
Write plain HTML with {{ placeholders }} for the number, customer, line items, subtotal, tax, total, and due date:
<article style="font-family: sans-serif; color: #111;">
<header style="display:flex; justify-content:space-between;">
<h1>Invoice {{ number }}</h1>
<div>Due {{ due_date }}</div>
</header>
<p>Billed to: {{ customer }}</p>
<table style="width:100%; border-collapse:collapse;">
<thead>
<tr>
<th style="text-align:left; border-bottom:1px solid #ccc;">Item</th>
<th style="text-align:right; border-bottom:1px solid #ccc;">Qty</th>
<th style="text-align:right; border-bottom:1px solid #ccc;">Price</th>
</tr>
</thead>
<tbody>
{{{ line_items }}}
</tbody>
</table>
<p style="text-align:right; margin-top:16px;">Subtotal: {{ subtotal }}</p>
<p style="text-align:right;">Tax: {{ tax }}</p>
<p style="text-align:right;"><strong>Total due: {{ total }}</strong></p>
</article>Generate the invoice PDF from Node.js
Using only fetch and node:fs/promises (both built into modern Node.js), POST the template and data to /api/v1/pdf and write the raw response bytes to a file:
import { writeFile } from "node:fs/promises";
const template = `<article style="font-family: sans-serif; color: #111;">
<header style="display:flex; justify-content:space-between;">
<h1>Invoice {{ number }}</h1>
<div>Due {{ due_date }}</div>
</header>
<p>Billed to: {{ customer }}</p>
<table style="width:100%; border-collapse:collapse;">
<thead>
<tr>
<th style="text-align:left; border-bottom:1px solid #ccc;">Item</th>
<th style="text-align:right; border-bottom:1px solid #ccc;">Qty</th>
<th style="text-align:right; border-bottom:1px solid #ccc;">Price</th>
</tr>
</thead>
<tbody>{{{ line_items }}}</tbody>
</table>
<p style="text-align:right; margin-top:16px;">Subtotal: {{ subtotal }}</p>
<p style="text-align:right;">Tax: {{ tax }}</p>
<p style="text-align:right;"><strong>Total due: {{ total }}</strong></p>
</article>`;
const lineItemsHtml = [
{ name: "Consulting — Sprint 12", qty: 1, price: "$1,200.00" },
{ name: "Support retainer", qty: 1, price: "$300.00" },
]
.map(
(item) =>
`<tr><td>${item.name}</td><td style="text-align:right;">${item.qty}</td><td style="text-align:right;">${item.price}</td></tr>`
)
.join("");
const response = await fetch("https://docweave.dev/api/v1/pdf", {
method: "POST",
headers: {
Authorization: "Bearer dw_live_your_key",
"Content-Type": "application/json",
Accept: "application/pdf",
},
body: JSON.stringify({
source: {
type: "template",
template,
data: {
number: "INV-042",
customer: "Acme Inc.",
due_date: "2026-08-01",
line_items: lineItemsHtml,
subtotal: "$1,500.00",
tax: "$120.00",
total: "$1,620.00",
},
},
idempotencyKey: "inv-042",
}),
});
if (!response.ok) {
throw new Error(`Docweave API error: ${response.status} ${await response.text()}`);
}
const pdfBuffer = Buffer.from(await response.arrayBuffer());
await writeFile("invoice-042.pdf", pdfBuffer);
console.log("Saved invoice-042.pdf");…or from an AI agent
The same invoice workflow works from an AI agent with no fetch code at all. Run npx @docweave/mcp and your agent gets a generate_pdf tool that wraps the same render orchestration as the REST endpoint:
// From an AI agent over MCP — no fetch/HTTP boilerplate:
// npx @docweave/mcp
generate_pdf({
source: {
type: "template",
template: "<h1>Invoice {{ number }}</h1><p>Billed to {{ customer }}</p><p>Total due: {{ total }}</p>",
data: { number: "INV-042", customer: "Acme Inc.", total: "$1,620.00" }
},
outputPath: "/tmp/invoice-042.pdf"
})FAQ
How do I generate an invoice PDF in Node.js without a headless browser?
POST your invoice template and billing JSON to the Docweave API with fetch: { source: { type: "template", template, data }, idempotencyKey }. Docweave binds the data into your template's {{ placeholders }} and renders it with Chromium on its own infrastructure, so your Node.js process never launches a browser.
What's the simplest way to fill an invoice template with data in Node.js?
Write an HTML template with {{ placeholders }} for the invoice number, customer, line items, subtotal, tax, total, and due date, then send it with a data object in the same request. No template engine to install — Docweave does the binding server-side.
How do I save the generated invoice PDF to disk in Node.js?
Request Accept: application/pdf, read the response body with response.arrayBuffer(), wrap it in a Buffer, and write it with node:fs/promises writeFile. The response bytes are the raw PDF — no decoding or base64 step needed.
How do I avoid billing twice for the same invoice on a retried request?
Pass an idempotencyKey (the invoice number is a natural choice, e.g. "inv-042"). If a retry sends the same key again, Docweave returns the original PDF instead of re-rendering and creating a second usage_event.
Related
Ready to generate invoice PDFs from your Node.js app?
Get an API key