The backend generates downloadable PDF invoices using WeasyPrint, an HTML/CSS-to-PDF rendering library. The PDF layout mirrors the frontend invoice preview template exactly.
- The frontend sends
GET /api/invoices/{id}/pdfwith the auth token. - The backend builds a self-contained HTML document with inline CSS that matches the invoice preview layout (company header, bill-to section, line items table, payment details, tax breakup).
- WeasyPrint renders the HTML to a PDF on A4 paper.
- The PDF is returned as a streaming download (
Content-Disposition: attachment). - The frontend creates a temporary blob URL and triggers the browser download.
GET /api/invoices/{invoice_id}/pdf
Authorization: Bearer <token>
Returns application/pdf with filename invoice_INV-XXXXXX.pdf.
WeasyPrint depends on Pango and GLib system libraries for text layout and font rendering.
brew install pangoThis pulls in all required dependencies (GLib, HarfBuzz, FreeType, Cairo, etc.).
The Dockerfile already includes the required packages:
apt-get install -y --no-install-recommends \
libpango-1.0-0 \
libpangocairo-1.0-0 \
libpangoft2-1.0-0 \
libgdk-pixbuf2.0-0 \
libffi-devapk add --no-cache pango fontconfig ttf-freefontDefined in backend/requirements.txt:
weasyprint==63.1
Install in the virtual environment:
cd backend
.venv/bin/pip install -r requirements.txtThe backend Dockerfile (backend/Dockerfile) already installs the system libraries. No extra steps are needed — just build normally:
docker build -t simple-backend ./backend| Problem | Solution |
|---|---|
OSError: cannot load library 'libgobject-2.0-0' |
Install Pango system libraries (see above) |
OSError: cannot load library 'libpango-1.0-0' |
Same — brew install pango on macOS |
| Fonts look wrong or use fallback glyphs | Install a font package (ttf-freefont on Alpine, fonts-liberation on Debian) |
| Currency symbols (₹, €, £) missing | Ensure a Unicode-capable font is available on the system |
| PDF is blank | Check WeasyPrint logs for CSS parsing errors — run the backend with LOG_LEVEL=debug |
The HTML template is defined in backend/src/api/routes/invoices.py in the _build_invoice_html() function. It uses inline CSS and mirrors the structure of the frontend's previewInvoice modal in frontend/src/pages/InvoicesPage.tsx. To change the PDF layout, edit the HTML/CSS in that function.