Generate invoice PDFs in Python
The simplest way to generate invoice PDFs in Python is to POST an invoice template and your billing JSON to the Docweave API: requests.post to /api/v1/pdf and write the returned bytes to a file — no headless browser to install or run yourself.
Invoice template example
Any HTML works as a template. Use {{ placeholders }} for the invoice number, customer, line items, subtotal, tax, total, and due date — the values you pass in data:
<article style="font-family: sans-serif;">
<header style="display:flex; justify-content:space-between;">
<h1>Invoice {{ number }}</h1>
<div>Due {{ due_date }}</div>
</header>
<p>Billed to: {{ customer }}</p>
<table style="width:100%; border-collapse:collapse;">
{{{ line_items }}}
</table>
<p style="text-align:right;">Subtotal: {{ subtotal }}</p>
<p style="text-align:right;">Tax: {{ tax }}</p>
<p style="text-align:right;"><strong>Total due: {{ total }}</strong></p>
</article>Generate the invoice PDF with Python
Send the template and data in the request body, then write the raw PDF bytes to disk:
import requests
API_KEY = "dw_live_your_key"
invoice_template = """
<article style="font-family: sans-serif;">
<header style="display:flex; justify-content:space-between;">
<h1>Invoice {{ number }}</h1>
<div>Due {{ due_date }}</div>
</header>
<p>Billed to: {{ customer }}</p>
<table style="width:100%; border-collapse:collapse;">
{{{ line_items }}}
</table>
<p style="text-align:right;">Subtotal: {{ subtotal }}</p>
<p style="text-align:right;">Tax: {{ tax }}</p>
<p style="text-align:right;"><strong>Total due: {{ total }}</strong></p>
</article>
"""
line_items_html = "".join(
f"<tr><td>{item['description']}</td><td style='text-align:right;'>{item['amount']}</td></tr>"
for item in [
{"description": "Design services", "amount": "$900.00"},
{"description": "Hosting (monthly)", "amount": "$140.00"},
]
)
response = requests.post(
"https://docweave.dev/api/v1/pdf",
headers={
"Authorization": f"Bearer {API_KEY}",
"Content-Type": "application/json",
"Accept": "application/pdf",
},
json={
"source": {
"type": "template",
"template": invoice_template,
"data": {
"number": "INV-042",
"customer": "Acme Inc.",
"due_date": "2026-08-01",
"line_items": line_items_html,
"subtotal": "$1,040.00",
"tax": "$83.20",
"total": "$1,123.20",
},
},
"idempotencyKey": "inv-042",
},
timeout=30,
)
response.raise_for_status()
with open("invoice.pdf", "wb") as f:
f.write(response.content)
print("Wrote invoice.pdf")…or from a Python AI agent, via MCP
If your agent runs in Python (LangChain, an MCP-native framework, or a custom client), the Docweave MCP server exposes a generate_pdf tool — the same underlying render, no HTTP boilerplate to write. Start it with npx @docweave/mcp:
# From a Python-based AI agent, over MCP — no HTTP plumbing:
generate_pdf({
"source": {
"type": "template",
"template": invoice_template,
"data": {
"number": "INV-042",
"customer": "Acme Inc.",
"due_date": "2026-08-01",
"line_items": line_items_html,
"subtotal": "$1,040.00",
"tax": "$83.20",
"total": "$1,123.20"
}
},
"outputPath": "/tmp/invoice-042.pdf"
})
# Any MCP client can call this tool once the server is registered — start it with:
# npx @docweave/mcpFAQ
What's the simplest way to generate an invoice PDF in Python?
POST an HTML invoice template and a JSON data object to /api/v1/pdf using the requests library, then write response.content to a file. Docweave binds your line items and totals into the {{ placeholders }} and returns the finished PDF — no headless browser to install or manage in your Python environment.
Do I need a PDF library like WeasyPrint or ReportLab installed?
No. Those libraries render the invoice layout locally and require you to manage fonts, CSS support, and a rendering engine yourself. Calling the Docweave API offloads that rendering — your Python code only needs an HTTP client and your invoice template.
Can I reuse the same invoice template for every customer?
Yes. Keep the template string constant and change only the "data" object per request — number, customer, line items, and totals. The layout stays identical across every invoice you generate.
How do I avoid double-billing if my Python script retries a failed request?
Pass an idempotencyKey (for example the invoice number) in the request body. A retry with the same key returns the original PDF instead of rendering — and billing — again. Rendering is billed per document, not per page, so a long itemized invoice costs the same as a short one.
Related
Ready to generate invoice PDFs from Python in production?
Get an API key