Invoices
Classic invoice PDF API
A clean multi-page invoice template for SaaS billing, agency work, and usage-based charges. Repeating table headers and stable totals make it safe for long line-item lists. Send this LaTeX template and JSON data to Texify in one /render request.
JSON schema
Fields this template expects.
| Field | Type | Required | Description |
|---|---|---|---|
| invoice_number | string | Yes | Human-readable invoice number. |
| seller | object | Yes | Company name, address, tax details, and email. |
| customer | object | Yes | Billing recipient details. |
| items | array | Yes | Line items with description, quantity, unit price, and totals. |
| currency | string | Yes | ISO currency code shown beside totals. |
| due_date | string | Yes | Payment due date in ISO format. |
API examples
POST LaTeX and JSON. Receive PDF bytes.
cat > classic-invoice-payload.json <<'JSON'
{
"entrypoint": "main.tex",
"resources": {
"main.tex": "\\documentclass[11pt]{article}\n\\usepackage[margin=0.7in]{geometry}\n\\usepackage{array,booktabs,xcolor}\n\\pagestyle{empty}\n\\begin{document}\n\\begin{flushright}\n{\\Huge \\textbf{Invoice}}\\\\[4pt]\n\\textbf{No.} [[ .invoice_number ]]\\\\\n\\textbf{Due} [[ .due_date ]]\n\\end{flushright}\n\\vspace{0.3in}\n\\noindent\\begin{minipage}[t]{0.48\\textwidth}\n\\textbf{From}\\\\\n[[ .seller.name ]]\\\\\n[[ .seller.address ]]\\\\\n[[ with .seller.tax_id ]]Tax ID: [[ . ]]\\\\[[ end ]]\n[[ with .seller.vat_id ]]VAT ID: [[ . ]]\\\\[[ end ]]\n\\end{minipage}\\hfill\n\\begin{minipage}[t]{0.48\\textwidth}\n\\textbf{Bill to}\\\\\n[[ .customer.name ]]\\\\\n[[ with .customer.address ]][[ . ]]\\\\[[ end ]]\n[[ with .customer.vat_id ]]VAT ID: [[ . ]]\\\\[[ end ]]\n\\end{minipage}\n\\vspace{0.4in}\n[[ with .subscription ]]\\noindent\\textbf{Subscription:} [[ .plan ]] ([[ .seats ]] seats, [[ .period ]])\\\\[8pt][[ end ]]\n\\begin{tabular}{>{\\raggedright\\arraybackslash}p{0.46\\textwidth}rrr}\n\\toprule\nDescription & Qty & Unit & Total\\\\\n\\midrule\n[[ range .items ]][[ .description ]] & [[ .quantity ]] & [[ .unit_price ]] & [[ .total ]]\\\\\n[[ end ]]\\bottomrule\n\\end{tabular}\n\\vspace{0.25in}\n\\begin{flushright}\n[[ with .subtotal ]]Subtotal: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n[[ with .tax ]]Tax: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n[[ with .vat_total ]]VAT: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n{\\Large \\textbf{Total: [[ .total ]] [[ .currency ]]}}\n\\end{flushright}\n\\end{document}"
},
"data": {
"invoice_number": "INV-2026-1042",
"seller": {
"name": "Northstar Labs",
"address": "18 King Street, London",
"tax_id": "GB123456789",
"vat_id": ""
},
"customer": {
"name": "Acme GmbH",
"address": "Mehringdamm 40, Berlin",
"vat_id": ""
},
"due_date": "2026-07-31",
"currency": "EUR",
"subscription": null,
"items": [
{
"description": "API platform subscription",
"quantity": 1,
"unit_price": 499,
"total": 499
},
{
"description": "PDF render overage",
"quantity": 4200,
"unit_price": 0.03,
"total": 126
}
],
"subtotal": 625,
"tax": 118.75,
"vat_total": null,
"total": 743.75
}
}
JSON
curl -sS -X POST https://api.texify.dev/render \
-H "Content-Type: application/json" \
--data @classic-invoice-payload.json \
--output classic-invoice.pdfimport json
import requests
payload = json.loads(r'''{
"entrypoint": "main.tex",
"resources": {
"main.tex": "\\documentclass[11pt]{article}\n\\usepackage[margin=0.7in]{geometry}\n\\usepackage{array,booktabs,xcolor}\n\\pagestyle{empty}\n\\begin{document}\n\\begin{flushright}\n{\\Huge \\textbf{Invoice}}\\\\[4pt]\n\\textbf{No.} [[ .invoice_number ]]\\\\\n\\textbf{Due} [[ .due_date ]]\n\\end{flushright}\n\\vspace{0.3in}\n\\noindent\\begin{minipage}[t]{0.48\\textwidth}\n\\textbf{From}\\\\\n[[ .seller.name ]]\\\\\n[[ .seller.address ]]\\\\\n[[ with .seller.tax_id ]]Tax ID: [[ . ]]\\\\[[ end ]]\n[[ with .seller.vat_id ]]VAT ID: [[ . ]]\\\\[[ end ]]\n\\end{minipage}\\hfill\n\\begin{minipage}[t]{0.48\\textwidth}\n\\textbf{Bill to}\\\\\n[[ .customer.name ]]\\\\\n[[ with .customer.address ]][[ . ]]\\\\[[ end ]]\n[[ with .customer.vat_id ]]VAT ID: [[ . ]]\\\\[[ end ]]\n\\end{minipage}\n\\vspace{0.4in}\n[[ with .subscription ]]\\noindent\\textbf{Subscription:} [[ .plan ]] ([[ .seats ]] seats, [[ .period ]])\\\\[8pt][[ end ]]\n\\begin{tabular}{>{\\raggedright\\arraybackslash}p{0.46\\textwidth}rrr}\n\\toprule\nDescription & Qty & Unit & Total\\\\\n\\midrule\n[[ range .items ]][[ .description ]] & [[ .quantity ]] & [[ .unit_price ]] & [[ .total ]]\\\\\n[[ end ]]\\bottomrule\n\\end{tabular}\n\\vspace{0.25in}\n\\begin{flushright}\n[[ with .subtotal ]]Subtotal: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n[[ with .tax ]]Tax: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n[[ with .vat_total ]]VAT: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n{\\Large \\textbf{Total: [[ .total ]] [[ .currency ]]}}\n\\end{flushright}\n\\end{document}"
},
"data": {
"invoice_number": "INV-2026-1042",
"seller": {
"name": "Northstar Labs",
"address": "18 King Street, London",
"tax_id": "GB123456789",
"vat_id": ""
},
"customer": {
"name": "Acme GmbH",
"address": "Mehringdamm 40, Berlin",
"vat_id": ""
},
"due_date": "2026-07-31",
"currency": "EUR",
"subscription": null,
"items": [
{
"description": "API platform subscription",
"quantity": 1,
"unit_price": 499,
"total": 499
},
{
"description": "PDF render overage",
"quantity": 4200,
"unit_price": 0.03,
"total": 126
}
],
"subtotal": 625,
"tax": 118.75,
"vat_total": null,
"total": 743.75
}
}''')
response = requests.post(
"https://api.texify.dev/render",
json=payload,
timeout=90,
)
response.raise_for_status()
with open("classic-invoice.pdf", "wb") as pdf:
pdf.write(response.content)import { writeFile } from "node:fs/promises";
const payload = {
"entrypoint": "main.tex",
"resources": {
"main.tex": "\\documentclass[11pt]{article}\n\\usepackage[margin=0.7in]{geometry}\n\\usepackage{array,booktabs,xcolor}\n\\pagestyle{empty}\n\\begin{document}\n\\begin{flushright}\n{\\Huge \\textbf{Invoice}}\\\\[4pt]\n\\textbf{No.} [[ .invoice_number ]]\\\\\n\\textbf{Due} [[ .due_date ]]\n\\end{flushright}\n\\vspace{0.3in}\n\\noindent\\begin{minipage}[t]{0.48\\textwidth}\n\\textbf{From}\\\\\n[[ .seller.name ]]\\\\\n[[ .seller.address ]]\\\\\n[[ with .seller.tax_id ]]Tax ID: [[ . ]]\\\\[[ end ]]\n[[ with .seller.vat_id ]]VAT ID: [[ . ]]\\\\[[ end ]]\n\\end{minipage}\\hfill\n\\begin{minipage}[t]{0.48\\textwidth}\n\\textbf{Bill to}\\\\\n[[ .customer.name ]]\\\\\n[[ with .customer.address ]][[ . ]]\\\\[[ end ]]\n[[ with .customer.vat_id ]]VAT ID: [[ . ]]\\\\[[ end ]]\n\\end{minipage}\n\\vspace{0.4in}\n[[ with .subscription ]]\\noindent\\textbf{Subscription:} [[ .plan ]] ([[ .seats ]] seats, [[ .period ]])\\\\[8pt][[ end ]]\n\\begin{tabular}{>{\\raggedright\\arraybackslash}p{0.46\\textwidth}rrr}\n\\toprule\nDescription & Qty & Unit & Total\\\\\n\\midrule\n[[ range .items ]][[ .description ]] & [[ .quantity ]] & [[ .unit_price ]] & [[ .total ]]\\\\\n[[ end ]]\\bottomrule\n\\end{tabular}\n\\vspace{0.25in}\n\\begin{flushright}\n[[ with .subtotal ]]Subtotal: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n[[ with .tax ]]Tax: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n[[ with .vat_total ]]VAT: [[ . ]] [[ $.currency ]]\\\\[[ end ]]\n{\\Large \\textbf{Total: [[ .total ]] [[ .currency ]]}}\n\\end{flushright}\n\\end{document}"
},
"data": {
"invoice_number": "INV-2026-1042",
"seller": {
"name": "Northstar Labs",
"address": "18 King Street, London",
"tax_id": "GB123456789",
"vat_id": ""
},
"customer": {
"name": "Acme GmbH",
"address": "Mehringdamm 40, Berlin",
"vat_id": ""
},
"due_date": "2026-07-31",
"currency": "EUR",
"subscription": null,
"items": [
{
"description": "API platform subscription",
"quantity": 1,
"unit_price": 499,
"total": 499
},
{
"description": "PDF render overage",
"quantity": 4200,
"unit_price": 0.03,
"total": 126
}
],
"subtotal": 625,
"tax": 118.75,
"vat_total": null,
"total": 743.75
}
};
const response = await fetch("https://api.texify.dev/render", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(payload),
signal: AbortSignal.timeout(90_000),
});
if (!response.ok) throw new Error(await response.text());
const pdf = Buffer.from(await response.arrayBuffer());
await writeFile("classic-invoice.pdf", pdf);The template
LaTeX source sent as resources["main.tex"].
\documentclass[11pt]{article}
\usepackage[margin=0.7in]{geometry}
\usepackage{array,booktabs,xcolor}
\pagestyle{empty}
\begin{document}
\begin{flushright}
{\Huge \textbf{Invoice}}\\[4pt]
\textbf{No.} [[ .invoice_number ]]\\
\textbf{Due} [[ .due_date ]]
\end{flushright}
\vspace{0.3in}
\noindent\begin{minipage}[t]{0.48\textwidth}
\textbf{From}\\
[[ .seller.name ]]\\
[[ .seller.address ]]\\
[[ with .seller.tax_id ]]Tax ID: [[ . ]]\\[[ end ]]
[[ with .seller.vat_id ]]VAT ID: [[ . ]]\\[[ end ]]
\end{minipage}\hfill
\begin{minipage}[t]{0.48\textwidth}
\textbf{Bill to}\\
[[ .customer.name ]]\\
[[ with .customer.address ]][[ . ]]\\[[ end ]]
[[ with .customer.vat_id ]]VAT ID: [[ . ]]\\[[ end ]]
\end{minipage}
\vspace{0.4in}
[[ with .subscription ]]\noindent\textbf{Subscription:} [[ .plan ]] ([[ .seats ]] seats, [[ .period ]])\\[8pt][[ end ]]
\begin{tabular}{>{\raggedright\arraybackslash}p{0.46\textwidth}rrr}
\toprule
Description & Qty & Unit & Total\\
\midrule
[[ range .items ]][[ .description ]] & [[ .quantity ]] & [[ .unit_price ]] & [[ .total ]]\\
[[ end ]]\bottomrule
\end{tabular}
\vspace{0.25in}
\begin{flushright}
[[ with .subtotal ]]Subtotal: [[ . ]] [[ $.currency ]]\\[[ end ]]
[[ with .tax ]]Tax: [[ . ]] [[ $.currency ]]\\[[ end ]]
[[ with .vat_total ]]VAT: [[ . ]] [[ $.currency ]]\\[[ end ]]
{\Large \textbf{Total: [[ .total ]] [[ .currency ]]}}
\end{flushright}
\end{document}Live render
Try sample data now.
Posts this LaTeX template and sample JSON to /render, then opens the returned PDF bytes.
{
"invoice_number": "INV-2026-1042",
"seller": {
"name": "Northstar Labs",
"address": "18 King Street, London",
"tax_id": "GB123456789",
"vat_id": ""
},
"customer": {
"name": "Acme GmbH",
"address": "Mehringdamm 40, Berlin",
"vat_id": ""
},
"due_date": "2026-07-31",
"currency": "EUR",
"subscription": null,
"items": [
{
"description": "API platform subscription",
"quantity": 1,
"unit_price": 499,
"total": 499
},
{
"description": "PDF render overage",
"quantity": 4200,
"unit_price": 0.03,
"total": 126
}
],
"subtotal": 625,
"tax": 118.75,
"vat_total": null,
"total": 743.75
}FAQ
FAQ
Can I use Classic invoice as a invoice PDF API?
Yes. Copy the LaTeX template, send it in resources with your data to /render, and Texify returns PDF bytes.
Can I change colors, copy, or field names?
Yes. Edit the LaTeX source and JSON placeholders to match your data model and brand before posting to /render.
Does this render real PDF text?
Yes. Texify compiles LaTeX to PDF, so text remains selectable, searchable, and stable across environments.
Related templates
More LaTeX PDF templates.
Invoices
VAT invoice
EU-style VAT invoice with tax ids, reverse-charge notes, currency totals, and clear remittance details. Built for marketplaces and B2B billing workflows.
Invoices
Subscription invoice
Subscription invoice for renewals, seat counts, credits, and prorated adjustments. Useful for product-led SaaS apps that need dependable customer PDFs.
Statements
Bank statement
Account statement with opening balance, transaction table, and closing summary. Designed for fintech apps, ledgers, and customer portals.