Ask Anvil

Answers to questions about automating PDFs, e-signatures, Webforms, and other paperwork problems.
PDFs
Categories

How do I generate a PDF financial report from live data?

The three-piece pattern

Template, data, API call. The template is a reusable design (HTML and CSS for free-form reports, structured Markdown for line-item statements, or a flat PDF with named field tags). The data is one JSON payload per report, pulled from QuickBooks, NetSuite, Snowflake, or whatever owns the numbers. The API call is a single POST that returns the rendered PDF binary.

A working example

Here is a Markdown-to-PDF request that produces a one-page profit and loss statement. Replace the values with whatever your ETL job or warehouse query returns.

curl -X POST https://app.useanvil.com/api/v1/generate-pdf \
  -u $ANVIL_API_KEY: \
  -H "Content-Type: application/json" \
  -d '{
    "title": "Q1 2026 Income Statement",
    "data": [
      { "heading": "Q1 2026 Income Statement" },
      { "label": "Period", "content": "Jan 1, 2026 - Mar 31, 2026" },
      {
        "table": {
          "rows": [
            ["Line Item", "Amount"],
            ["Revenue", "$1,250,000"],
            ["Operating Expenses", "$820,000"],
            ["Net Income", "$430,000"]
          ],
          "firstRowHeaders": true,
          "rowGridlines": true
        }
      }
    ]
  }' \
  --output q1-pnl.pdf

The response is binary PDF bytes, so save it without text encoding or you will get a corrupt file (Anvil's docs flag this explicitly in the troubleshooting section). The endpoint is the same /api/v1/generate-pdf whether you send Markdown (the array shape above) or HTML and CSS in a data: { html, css } object.

What to watch for

Three things tend to bite once these reports go to production.

1. Idempotency. A failed run should not generate duplicate Q1 statements. Generate a deterministic filename from the period and entity ID (for example, pnl-2026-q1-acme.pdf) so retries overwrite the same file rather than creating a second copy auditors have to reconcile.

2. Audit trail. Finance reports often need a versioned, immutable record. Store both the rendered PDF and the source JSON payload alongside it. That is what SOC 2 reviewers and external auditors ask for when they want to know how a number ended up on a page.

3. Format numbers at the data layer, not the template. Currency symbols, thousands separators, and percentage formatting belong in the SQL or application code, not in the template string. The moment you reuse the same template for a EUR or GBP report, a hard-coded "$" in the template breaks.

When other tools fit better

HTML-to-PDF via a headless browser (Puppeteer or Playwright) gives you full CSS control but pushes template authoring onto engineers. Python libraries like ReportLab and WeasyPrint are strong for highly programmatic, table-heavy reports. Template-based JSON-to-PDF APIs (Anvil's PDF Generation API, APITemplate.io) sit in the middle, with the trade-off being how much the template language can express. If your template owner is the finance ops lead and you want them to change report layout without a deploy, the JSON-to-PDF route is the friendliest.

Back to All Questions

The fastest way to build software for documents

Anvil Document SDK is a comprehensive toolbox for product teams launching document flows where PDF filling, signing, and complex conditional scenarios are necessary.
Explore Anvil
Anvil Webforms