I made an invoice PDF API that doesn't need a headless browser

작성자

카테고리:

← 피드로
DEV Community · Rahul · 2026-07-27 개발(SW)

Rahul

Generating a PDF shouldn’t require a headless browser

Every time I needed to generate an invoice or receipt PDF, the options were:
wrestle a low-level PDF library, fight a templating engine, or spin up headless
Chromium (slow, heavy, breaks on fonts, painful to host). For a document, that
felt absurd.

So I built InvoicePDF: POST JSON, get a clean invoice PDF back.
That’s the whole thing.

curl -X POST https://invoicepdf-app.azurewebsites.net/invoice \
  -H "Content-Type: application/json" \
  -d '{
    "number": "INV-2026-001",
    "currency": "USD",
    "seller_name": "Your Company LLC",
    "buyer_name": "Acme Corp",
    "items": [
      { "description": "Consulting (hours)", "quantity": 8, "unit_price": 120 },
      { "description": "Software license", "quantity": 1, "unit_price": 299 }
    ],
    "tax_rate_percent": 10,
    "notes": "Thank you!"
  }' --output invoice.pdf

Enter fullscreen mode Exit fullscreen mode

Why pure Python (no chromium)

It’s built on fpdf2 — a pure-Python PDF library — so there’s no headless
browser and no system dependencies.
That means it starts instantly, uses
almost no memory, and deploys on a free tier like a static app. For structured
documents (invoices, receipts, statements), you don’t need a browser; you need
correct layout and correct math.

The money math is exact

Financial documents can’t have floating-point drift. InvoicePDF does all money
as integer minor units (cents/paise) internally, so $27.00 subtotal + 10%
tax
is exactly $29.70 — never $29.700000001. It handles multiple currencies
(including zero-decimal ones like JPY), fractional quantities (e.g. hours), tax,
notes, and due dates.

Try it / use it

Free tier is 100 invoices/mo, no signup. If you generate a lot, there’s a cheap
paid tier.

What would make this actually useful in your stack — logo/branding, a hosted
template editor, webhooks? Genuinely curious — feedback welcome.

원문에서 계속 ↗

코멘트

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다