Texify

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.

Subscription invoice PDF preview

JSON schema

Fields this template expects.

FieldTypeRequiredDescription
invoice_numberstringYesHuman-readable invoice number.
sellerobjectYesCompany name, address, tax details, and email.
customerobjectYesBilling recipient details.
itemsarrayYesLine items with description, quantity, unit price, and totals.
currencystringYesISO currency code shown beside totals.
due_datestringYesPayment due date in ISO format.

API examples

POST LaTeX and JSON. Receive PDF bytes.

curl
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.pdf
Python
import 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)
Node fetch
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"].

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.

Sample 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
}

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.