Invoices
Subscription invoice PDF API
Subscription invoice for renewals, seat counts, credits, and prorated adjustments. Useful for product-led SaaS apps that need dependable customer PDFs. 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 > subscription-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": "SUB-2026-219",
"seller": {
"name": "VectorDesk Inc.",
"address": "44 Market St, San Francisco",
"tax_id": "",
"vat_id": ""
},
"customer": {
"name": "River Analytics",
"address": "12 Harbor Ave, Boston",
"vat_id": ""
},
"due_date": "2026-07-20",
"currency": "USD",
"subscription": {
"plan": "Scale",
"seats": 34,
"period": "2026-07"
},
"items": [
{
"description": "Scale plan",
"quantity": 1,
"unit_price": 1200,
"total": 1200
},
{
"description": "Proration credit",
"quantity": 1,
"unit_price": -180,
"total": -180
}
],
"subtotal": null,
"tax": null,
"vat_total": null,
"total": 1020
}
}
JSON
curl -sS -X POST https://api.texify.dev/render \
-H "Content-Type: application/json" \
--data @subscription-invoice-payload.json \
--output subscription-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": "SUB-2026-219",
"seller": {
"name": "VectorDesk Inc.",
"address": "44 Market St, San Francisco",
"tax_id": "",
"vat_id": ""
},
"customer": {
"name": "River Analytics",
"address": "12 Harbor Ave, Boston",
"vat_id": ""
},
"due_date": "2026-07-20",
"currency": "USD",
"subscription": {
"plan": "Scale",
"seats": 34,
"period": "2026-07"
},
"items": [
{
"description": "Scale plan",
"quantity": 1,
"unit_price": 1200,
"total": 1200
},
{
"description": "Proration credit",
"quantity": 1,
"unit_price": -180,
"total": -180
}
],
"subtotal": null,
"tax": null,
"vat_total": null,
"total": 1020
}
}''')
response = requests.post(
"https://api.texify.dev/render",
json=payload,
timeout=90,
)
response.raise_for_status()
with open("subscription-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": "SUB-2026-219",
"seller": {
"name": "VectorDesk Inc.",
"address": "44 Market St, San Francisco",
"tax_id": "",
"vat_id": ""
},
"customer": {
"name": "River Analytics",
"address": "12 Harbor Ave, Boston",
"vat_id": ""
},
"due_date": "2026-07-20",
"currency": "USD",
"subscription": {
"plan": "Scale",
"seats": 34,
"period": "2026-07"
},
"items": [
{
"description": "Scale plan",
"quantity": 1,
"unit_price": 1200,
"total": 1200
},
{
"description": "Proration credit",
"quantity": 1,
"unit_price": -180,
"total": -180
}
],
"subtotal": null,
"tax": null,
"vat_total": null,
"total": 1020
}
};
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("subscription-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": "SUB-2026-219",
"seller": {
"name": "VectorDesk Inc.",
"address": "44 Market St, San Francisco",
"tax_id": "",
"vat_id": ""
},
"customer": {
"name": "River Analytics",
"address": "12 Harbor Ave, Boston",
"vat_id": ""
},
"due_date": "2026-07-20",
"currency": "USD",
"subscription": {
"plan": "Scale",
"seats": 34,
"period": "2026-07"
},
"items": [
{
"description": "Scale plan",
"quantity": 1,
"unit_price": 1200,
"total": 1200
},
{
"description": "Proration credit",
"quantity": 1,
"unit_price": -180,
"total": -180
}
],
"subtotal": null,
"tax": null,
"vat_total": null,
"total": 1020
}FAQ
FAQ
Can I use Subscription invoice as a subscription 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
Classic invoice
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.
Reports
Monthly report
Executive monthly report with KPI table, narrative sections, and chart-ready data blocks. Built for customer-facing analytics exports.
Statements
Bank statement
Account statement with opening balance, transaction table, and closing summary. Designed for fintech apps, ledgers, and customer portals.