Every backend eventually has to spit out a PDF β an invoice, a receipt, a report, a certificate. And in every language, the options are bad:
- Headless Chrome / Puppeteer β you render HTML to PDF. Works until your data gets long: tables split across pages, fonts go missing, and you're babysitting a browser farm in production.
- Native libraries (ReportLab in Python, PDFKit in Node, FPDF in PHP, gofpdf in Go) β you position everything by hand in code. Generic fonts, fragile layouts, and the design lives in your codebase forever.
There's a cleaner separation: design the document once, then feed it data over HTTP. Because it's just a REST call, the exact same approach works in any language.
The idea: template + data β PDF
- Design a reusable template once β visually, or by describing it to an AI β with placeholders like
{{customer}}and{{total}}. -
POSTyour JSON to one endpoint with the template ID. - Get back a finished, editable PDF.
No HTML/CSS, no headless browser, no fonts to ship. Here's the same request in five languages.
curl
curl https://api.pdfmakerapi.com/v1/render \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{ "template_id": "invoice_default",
"data": { "number": "INV-1042", "customer": "Acme Inc.", "total": 49.00 } }' \
--output invoice.pdf
Node.js
const res = await fetch("https://api.pdfmakerapi.com/v1/render", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.PDF_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
template_id: "invoice_default",
data: { number: "INV-1042", customer: "Acme Inc.", total: 49.0 },
}),
});
require("fs").writeFileSync("invoice.pdf", Buffer.from(await res.arrayBuffer()));
Python
import os, requests
res = requests.post(
"https://api.pdfmakerapi.com/v1/render",
headers={"Authorization": f"Bearer {os.environ['PDF_API_KEY']}"},
json={
"template_id": "invoice_default",
"data": {"number": "INV-1042", "customer": "Acme Inc.", "total": 49.00},
},
)
open("invoice.pdf", "wb").write(res.content)
PHP
<?php
$res = file_get_contents("https://api.pdfmakerapi.com/v1/render", false, stream_context_create([
"http" => [
"method" => "POST",
"header" => "Authorization: Bearer {$_ENV['PDF_API_KEY']}\r\nContent-Type: application/json",
"content" => json_encode([
"template_id" => "invoice_default",
"data" => ["number" => "INV-1042", "customer" => "Acme Inc.", "total" => 49.00],
]),
],
]));
file_put_contents("invoice.pdf", $res);
Go
body, _ := json.Marshal(map[string]any{
"template_id": "invoice_default",
"data": map[string]any{"number": "INV-1042", "customer": "Acme Inc.", "total": 49.00},
})
req, _ := http.NewRequest("POST", "https://api.pdfmakerapi.com/v1/render", bytes.NewReader(body))
req.Header.Set("Authorization", "Bearer "+os.Getenv("PDF_API_KEY"))
req.Header.Set("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
out, _ := os.Create("invoice.pdf")
io.Copy(out, res.Body)
Same JSON, same endpoint, five languages. The PDF comes back in the response body.
Where the template comes from
You don't write HTML. You design the template in a visual, drag-and-drop editor β drop in text, tables, images, and {{variables}} β or describe it in plain English and let the AI build it. Change the design later without touching your code; your request body stays the same.
And because it renders from a structured template (not a screenshot of a webpage), layouts don't break when the data changes β and there's no headless browser, so it generates thousands of PDFs in seconds.
Generating in bulk
It's just HTTP, so loop your data:
for inv in invoices:
pdf = requests.post(URL, headers=H, json={
"template_id": "invoice_default", "data": inv,
}).content
open(f"{inv['number']}.pdf", "wb").write(pdf)
Try it
PDFMakerAPI is free to start β 100 PDFs/month, no card. Design a template, grab an API key, and you're rendering PDFs from any language in a few minutes. You can also generate from no-code tools (Zapier, Make, n8n) or straight from AI agents (Claude, ChatGPT) β same templates, same output.
What's the worst PDF-generation setup you've had to maintain? Curious what people are running.












