Finance

Statement of account PDF generator API

A customer statement with opening and closing balances, every invoice and payment, and an aging summary.

Give customers a clear picture of what they owe. This statement lists every invoice and payment in the period with a running balance, summary boxes for the opening balance, invoiced amount, payments and balance due, and an aging breakdown.

Pull the data from your accounting system and send every customer a statement at month end with one API call each.

Generate a Statement of Account PDF via the API

POST your data to /api/v1/generate and get a PDF back. Copy-paste an example, swap in your API key, and loop over a list to render thousands — one statement of account per record.

curl -X POST https://pdfgen.com/api/v1/generate \
-H "Authorization: Bearer pdfg_live_xxx" \
-H "Content-Type: application/json" \
-d '{
"html": "<div style=\"max-width:780px;margin:0 auto;padding:44px;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica,Arial,sans-serif;color:#111827;font-size:13px;\">\n <div style=\"display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:26px;\">\n <div>\n <h1 style=\"font-size:22px;font-weight:800;margin:0;\">{{company.name}}</h1>\n <p style=\"margin:4px 0 0;font-size:12px;color:#6b7280;white-space:pre-line;\">{{company.address}}</p>\n </div>\n <div style=\"text-align:right;\">\n <h2 style=\"font-size:20px;font-weight:800;letter-spacing:1px;margin:0;color:#0369a1;\">STATEMENT OF ACCOUNT</h2>\n <p style=\"margin:6px 0 0;color:#6b7280;\">{{formatDate periodStart}} – {{formatDate periodEnd}}</p>\n </div>\n </div>\n <div style=\"display:flex;justify-content:space-between;margin-bottom:20px;\">\n <div>\n <p style=\"font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#9ca3af;font-weight:700;margin:0 0 8px;\">Customer</p>\n <p style=\"margin:0;font-weight:700;\">{{customer.name}}</p>\n <p style=\"margin:2px 0 0;color:#6b7280;white-space:pre-line;\">{{customer.address}}</p>\n </div>\n <div style=\"text-align:right;color:#6b7280;\">\n <p style=\"margin:0;\">Account <strong style=\"color:#111827;\">{{accountNumber}}</strong></p>\n <p style=\"margin:2px 0 0;\">Statement date <strong style=\"color:#111827;\">{{formatDate statementDate}}</strong></p>\n </div>\n </div>\n <div style=\"display:flex;gap:10px;margin-bottom:22px;\">\n <div style=\"flex:1;background:#f9fafb;border-radius:8px;padding:12px;\"><p style=\"margin:0;font-size:11px;color:#6b7280;\">Opening balance</p><p style=\"margin:4px 0 0;font-size:16px;font-weight:700;\">{{formatCurrency openingBalance currency}}</p></div>\n <div style=\"flex:1;background:#f9fafb;border-radius:8px;padding:12px;\"><p style=\"margin:0;font-size:11px;color:#6b7280;\">Invoiced</p><p style=\"margin:4px 0 0;font-size:16px;font-weight:700;\">{{formatCurrency invoiced currency}}</p></div>\n <div style=\"flex:1;background:#f9fafb;border-radius:8px;padding:12px;\"><p style=\"margin:0;font-size:11px;color:#6b7280;\">Payments</p><p style=\"margin:4px 0 0;font-size:16px;font-weight:700;\">{{formatCurrency payments currency}}</p></div>\n <div style=\"flex:1;background:#0369a1;color:#fff;border-radius:8px;padding:12px;\"><p style=\"margin:0;font-size:11px;opacity:.85;\">Balance due</p><p style=\"margin:4px 0 0;font-size:16px;font-weight:800;\">{{formatCurrency balanceDue currency}}</p></div>\n </div>\n <table style=\"width:100%;border-collapse:collapse;font-size:inherit;line-height:inherit;\">\n <thead>\n <tr style=\"text-align:left;border-bottom:2px solid #e5e7eb;\">\n <th style=\"padding:8px 6px;\">Date</th>\n <th style=\"padding:8px 6px;\">Reference</th>\n <th style=\"padding:8px 6px;\">Description</th>\n <th style=\"padding:8px 6px;text-align:right;\">Debit</th>\n <th style=\"padding:8px 6px;text-align:right;\">Credit</th>\n <th style=\"padding:8px 6px;text-align:right;\">Balance</th>\n </tr>\n </thead>\n <tbody>\n {{#each transactions}}\n <tr>\n <td style=\"padding:8px 6px;border-bottom:1px solid #f3f4f6;white-space:nowrap;\">{{formatDate date}}</td>\n <td style=\"padding:8px 6px;border-bottom:1px solid #f3f4f6;font-family:monospace;color:#6b7280;\">{{reference}}</td>\n <td style=\"padding:8px 6px;border-bottom:1px solid #f3f4f6;\">{{description}}</td>\n <td style=\"padding:8px 6px;border-bottom:1px solid #f3f4f6;text-align:right;\">{{formatCurrency debit ../currency}}</td>\n <td style=\"padding:8px 6px;border-bottom:1px solid #f3f4f6;text-align:right;color:#15803d;\">{{formatCurrency credit ../currency}}</td>\n <td style=\"padding:8px 6px;border-bottom:1px solid #f3f4f6;text-align:right;font-weight:600;\">{{formatCurrency balance ../currency}}</td>\n </tr>\n {{/each}}\n </tbody>\n </table>\n <p style=\"font-size:11px;text-transform:uppercase;letter-spacing:1.5px;color:#9ca3af;font-weight:700;margin:0 0 8px;margin-top:24px;\">Aging</p>\n <table style=\"width:100%;border-collapse:collapse;text-align:center;font-size:inherit;line-height:inherit;\">\n <tr style=\"color:#6b7280;font-size:11px;\"><td style=\"padding:6px;border:1px solid #e5e7eb;\">Current</td><td style=\"padding:6px;border:1px solid #e5e7eb;\">1–30 days</td><td style=\"padding:6px;border:1px solid #e5e7eb;\">31–60 days</td><td style=\"padding:6px;border:1px solid #e5e7eb;\">61–90 days</td><td style=\"padding:6px;border:1px solid #e5e7eb;\">90+ days</td></tr>\n <tr style=\"font-weight:600;\"><td style=\"padding:8px;border:1px solid #e5e7eb;\">{{formatCurrency aging.current currency}}</td><td style=\"padding:8px;border:1px solid #e5e7eb;\">{{formatCurrency aging.days30 currency}}</td><td style=\"padding:8px;border:1px solid #e5e7eb;\">{{formatCurrency aging.days60 currency}}</td><td style=\"padding:8px;border:1px solid #e5e7eb;\">{{formatCurrency aging.days90 currency}}</td><td style=\"padding:8px;border:1px solid #e5e7eb;\">{{formatCurrency aging.over90 currency}}</td></tr>\n </table>\n <p style=\"margin:22px 0 0;font-size:12px;color:#6b7280;\">{{note}}</p>\n</div>",
"engine": "handlebars",
"format": "A4",
"data": {
"company": {
"name": "Northwind Studio",
"address": "120 Market St\nSan Francisco, CA 94103"
},
"customer": {
"name": "Acme Corp",
"address": "88 Industrial Way\nAustin, TX 78701"
},
"accountNumber": "ACME-0042",
"statementDate": "2026-10-31",
"periodStart": "2026-10-01",
"periodEnd": "2026-10-31",
"currency": "USD",
"openingBalance": 4200,
"invoiced": 9650,
"payments": 7200,
"balanceDue": 6650,
"transactions": [
{
"date": "2026-10-01",
"reference": "BAL",
"description": "Opening balance",
"balance": 4200
},
{
"date": "2026-10-03",
"reference": "INV-2026-019",
"description": "Website maintenance, October",
"debit": 1200,
"balance": 5400
},
{
"date": "2026-10-08",
"reference": "PAY-8812",
"description": "Payment received, thank you",
"credit": 4200,
"balance": 1200
},
{
"date": "2026-10-14",
"reference": "INV-2026-021",
"description": "Brand refresh, phase 1",
"debit": 6050,
"balance": 7250
},
{
"date": "2026-10-22",
"reference": "PAY-8840",
"description": "Payment received, thank you",
"credit": 3000,
"balance": 4250
},
{
"date": "2026-10-28",
"reference": "INV-2026-024",
"description": "Hosting and support, Q4",
"debit": 2400,
"balance": 6650
}
],
"aging": {
"current": 2400,
"days30": 4250,
"days60": 0,
"days90": 0,
"over90": 0
},
"note": "Please pay the balance due by November 14, 2026. Questions about this statement? Email billing@northwind.studio."
}
}' --output statement-of-account.pdf

Working in another language? Follow a full guide for your stack:

What you can build

  • Sending monthly statements to all customers automatically
  • Chasing overdue balances with a clear aging summary
  • Wholesalers and distributors with many open invoices per customer
  • Agencies reconciling retainers and payments with clients

Frequently asked questions

Where does the data come from?
Any system that has invoices and payments — your accounting tool, billing database or ERP. Pass the transactions and totals as JSON.
Can it show the aging of overdue amounts?
Yes — the aging table shows current, 1–30, 31–60, 61–90 and 90+ day buckets from the values you pass.
Can I send statements on a schedule?
Yes — run a monthly job (or a Zapier / Make schedule) that calls /api/v1/generate for each customer and emails the PDF.

Related templates

Ship your statement of account PDF endpoint today

Generate this template with AI, tweak it to match your brand, then render at scale with a single API call — no headless browsers to babysit.