PDF invoices from HTML
One HTML template, a dictionary of values, a PDF per customer. Rendered in a real browser, so your CSS prints the way it previews.
1. Save the template
The html engine takes a whole document or a fragment, with {{placeholders}} wherever a value goes (escaped) and {{{raw}}} for markup you build yourself, such as the line-item rows.
curl -X POST https://api.imageapis.com/v1/templates \
-H 'X-API-Key: YOUR_KEY' -H 'Content-Type: application/json' \
-d @- <<'JSON'
{
"name": "Invoice", "engine": "html", "width": 794, "height": 1123,
"html": "<h1>Invoice {{number}}</h1><div class=muted>Issued {{issued}} · due {{due}}</div><table><tr><th>Item</th><th>Qty</th><th>Amount</th></tr>{{{rows}}}</table><p class=total>Total {{total}}</p>",
"css": "body{font-family:Inter,sans-serif;color:#0f172a} h1{font-size:28px;margin:0 0 4px} .muted{color:#64748b} table{width:100%;border-collapse:collapse;margin-top:24px} th,td{text-align:left;padding:8px 0;border-bottom:1px solid #e2e8f0} .total{font-weight:700;font-size:20px;margin-top:20px}"
}
JSON
2. Render in the background
curl -X POST https://api.imageapis.com/v1/pdfs \
-H 'X-API-Key: YOUR_KEY' -H 'Content-Type: application/json' \
-d '{
"template": "tpl_…",
"variables": {
"number": "#1042", "issued": "10 Oct 2026", "due": "9 Nov 2026", "total": "$3,320.00",
"rows": "<tr><td>Design sprint</td><td>1</td><td>$3,200.00</td></tr><tr><td>Hosting</td><td>1</td><td>$120.00</td></tr>"
},
"format": "A4", "margin": "20mm",
"webhook_url": "https://example.com/hooks/invoices",
"metadata": { "customer_id": 8812 }
}'
The answer is 202 with status: "pending" and the final url. When the PDF is done, the webhook receives { "event": "render.completed", "pdf": { … "pages": 1, "units": 1, "metadata": { "customer_id": 8812 } } }. The record's pages is what you were charged.
Page breaks and paper
format is A4, A3, A5, Letter, Legal or Tabloid, with landscape and a single margin for all sides. Use page-break-before: always in your CSS to start a new page, and @page { size: … } rules apply when you leave format out. A layer template without format prints at its own pixel size on one page, which is how certificates are done.
Keeping copies
PDFs are hosted 30 days on the free plan and a year on paid plans. Download them into your own storage when they are delivered, or send "response": "binary" to get the file in the same request.