Yet in many C# applications, generating a clean and reliable invoice PDF still feels harder than it should be.
Between PDF libraries, HTML-to-PDF tools, layout bugs, and infrastructure issues, what looks like a simple feature often turns into a maintenance nightmare.
In this article, I’ll show you how to generate invoice PDFs in C# using an API-first approach, with:
- HTML templates
- dynamic JSON data
- no PDF logic in your backend
Why invoice PDF generation is still painful in .NET
If you’ve worked on invoice generation before, this probably sounds familiar:
- Layout breaks when data grows
- PDF libraries tightly coupled to business logic
- Headless browsers crashing in production
- Every layout change requires a redeploy
- Only developers can edit templates
Invoices evolve constantly: branding, legal mentions, taxes, languages.
Embedding all of that directly inside your backend does not scale.
That’s why treating document generation as a separate service makes a huge difference.
The API-first approach
Instead of generating PDFs inside your C# application, we’ll:
(using a document generation API like TemplateMaster)
- Create an HTML invoice template
- Store and version it in TemplateMaster
- Send invoice data as JSON
- Let the API generate the PDF
- Receive a ready-to-use file
Your backend focuses on business logic.
The document layer becomes external, reusable, and maintainable.
Step 1 – Create an invoice HTML template
Here’s a simplified invoice template example:
<h1>Invoice #{{invoiceNumber}}</h1>
<p>
<strong>Customer</strong><br />
{{customer.name}}<br />
{{customer.address}}
</p>
<table width="100%" border="1" cellspacing="0" cellpadding="8">
<thead>
<tr>
<th>Description</th>
<th>Qty</th>
<th>Unit price</th>
<th>Total</th>
</tr>
</thead>
<tbody>
{{#each items}}
<tr>
<td>{{description}}</td>
<td>{{quantity}}</td>
<td>{{price}} €</td>
<td>{{total}} €</td>
</tr>
{{/each}}
</tbody>
</table>
<p>
<strong>Total amount:</strong> {{totalAmount}} €
</p>
This template:
- is readable
- supports loops
- can be edited by non-developers
- doesn’t require any C# change when updated
Step 2 – Upload the template to TemplateMaster
Once uploaded to TemplateMaster:
- the template is versioned
- editable via a visual editor
- reusable across environments
Each template has a unique identifier, for example:
813a5147-a68c-4c37-b194-124100368efa
This identifier will be used by your backend when generating PDFs.
Step 3 – Prepare invoice data in C#
Now let’s build the invoice payload in C#:
var invoiceData ={
"templateCode": "813a5147-a68c-4c37-b194-124100368efa",
"version": 0,
"data": {
"name": "John Doe",
"address": "1234 Main St, Anytown, AN 12345",
"items": [
{
"description": "Product 1",
"quantity": 2,
"price": 30.00
},
{
"description": "Product 2",
"quantity": 1,
"price": 15.50
}
],
"total": 75.50,
"date": "2023-07-30",
"metadata": {
"title": "Service Agreement",
"author": "TemplateMaster",
"subject": "Commercial agreement between TemplateMaster and ABC Company",
"keywords": ["contract", "services", "TemplateMaster", "ABC Company"],
"creator": "TemplateMaster API",
"producer": "TemplateMaster PDF Engine",
"createdAt": "2025-10-14T10:30:00Z",
"modifiedAt": "2025-10-14T10:31:00Z"
},
"indexes":[
{ "DocumentType": "Facture" },
{ "InvoiceNumber": "F2025-00123" },
{ "CreatedBy": "TemplateMaster" }
]
}
};
This object matches the variables used in the HTML template.
No formatting logic.
No PDF concerns.
Just data.
Step 4 – Call the PDF generation API
Now we send the template ID and data to TemplateMaster.
using var client = new HttpClient();
var request = new
{
templateId = "invoice-default",
data = invoiceData
};
var response = await client.PostAsJsonAsync(
"https://api.templatemaster.io/pdf/generate",
request
);
var pdfBytes = await response.Content.ReadAsByteArrayAsync();
File.WriteAllBytes("invoice.pdf", pdfBytes);
That’s all it takes.
No PDF engine.
No headless browser.
No rendering logic in your backend.
Step 5 – Use the PDF anywhere
Once generated, the PDF can be:
- emailed to customers
- stored for accounting
- archived for compliance
- exposed via an API
When the invoice layout changes?
- Update the template
- No backend redeploy
- No code change
Why this approach scales better
Approach Problems
PDF libraries Tight coupling, hard to evolve
HTML-to-PDF in backend Infra heavy, unstable
API-based generation Clean, scalable, maintainable
This pattern works especially well when:
- invoices evolve frequently
- multiple teams collaborate
- you run a SaaS or multi-tenant system
Final thoughts
Invoice PDF generation shouldn’t slow your team down.
By externalizing document generation behind an API, you:
- reduce complexity
- move faster
- keep your backend clean
If you’re building a serious C# application, this is a pattern worth adopting early.
Try it locally
If you want to experiment with this approach, I’m using
TemplateMaster to manage templates and generate PDFs via API.
You can try it without changing your C# setup or PDF stack.
Top comments (0)