The journal · 13 October 2026 · 9 min read
Invoice PDF API for generating invoice PDFs from your own billing data
Two very different jobs get called "invoice PDF API": fetching the PDF a billing platform already made, and generating your own from an HTML template. Here is when to use each, with the Stripe and QuickBooks endpoints and the render call, plus how to keep a record every finance team eventually needs.
Live demo
Runs in your browser. Nothing is uploaded. One PDF free to try, then a plan.
Your HTML
Live preview
Your PDF is downloading. That was the free one. The Starter plan converts as many as you need, for $49 a month or $288 a year, half price.
See the plan"Invoice PDF API" gets used for two jobs that barely overlap. One is fetching a PDF a billing platform has already generated for you, the Stripe or QuickBooks invoice, over its API. The other is generating your own invoice PDF from an HTML template you control, because the platform version does not match your brand or you bill outside any of them. They need different tools, and picking the wrong one is where teams waste a week. Here is the map, with the actual endpoints and the render call, plus the record keeping a finance team always ends up needing.
The short version
If your invoices already live in Stripe or QuickBooks, do not build a PDF renderer. Both expose the finished PDF over their API: Stripe returns an invoice_pdf URL on the invoice object, and QuickBooks Online has a dedicated PDF endpoint. Fetch it and store it. Build your own renderer only when you need a branded or custom invoice that no platform produces, when you bill from your own system, or when you need a document that matches your HTML invoice exactly. For that, render the HTML you already have in a real browser engine and keep a timestamped copy for the audit trail. Do not hand build PDFs with a drawing library unless you enjoy pain.
If the invoice is in Stripe, fetch it instead of rendering
Stripe generates a PDF for every finalized invoice. You do not need to draw anything. Retrieve the invoice and read invoice_pdf, a short-lived URL to the PDF file, alongside hosted_invoice_url for the web version.
// Node, Stripe SDK
const invoice = await stripe.invoices.retrieve('in_1QabcABC');
// invoice.invoice_pdf -> URL to the PDF Stripe generated
// invoice.hosted_invoice_url -> the hosted web copy
const pdf = await fetch(invoice.invoice_pdf);
const buffer = Buffer.from(await pdf.arrayBuffer());
// store buffer in your own bucket for your records
The catch worth knowing: invoice_pdf is only present once the invoice is finalized, and the URL is temporary, so download and store the bytes rather than saving the link. Stripe controls the layout, which is a feature if you are fine with the Stripe look and a limitation if finance wants your logo, your terms and your column order. If the standard Stripe invoice is acceptable, this is the whole job and you should stop here.
The QuickBooks PDF endpoint for invoices that already live in QuickBooks
QuickBooks Online exposes the invoice PDF directly. Send a GET to the invoice PDF path with an Accept: application/pdf header and you get the file back.
GET https://quickbooks.api.intuit.com/v3/company/{realmId}/invoice/{invoiceId}/pdf
Authorization: Bearer {oauth2_access_token}
Accept: application/pdf
The response body is the PDF itself. As with Stripe, the layout is QuickBooks' own, driven by the template settings in the account, so you get consistency and limited control. For teams whose books already live in QuickBooks, pulling the PDF from here keeps one source of truth and avoids a second layout to maintain. If you also need the invoice data as structured rows rather than a document, that is a different pipeline, and the finance side of it, chasing what is owed, is its own product category.
When you render your own with HTML in and PDF out
Fetching works only when a platform already made the invoice. Plenty of teams bill from their own system, need a branded document Stripe cannot produce, or want the PDF to match the HTML invoice they already show in the app. In that case you generate the PDF yourself, and the sane way to do it is to render the HTML you already have rather than draw the document by hand with a library like PDFKit.
You almost certainly already have the invoice as an HTML template: it is what your app shows on the invoice detail page. Render that same markup to PDF and the document matches the screen for free. The trap is using a renderer that does not run a real browser: dompdf, wkhtmltopdf and similar cannot handle modern CSS, so an invoice built with flexbox or grid comes out broken. Render in actual Chromium instead. From any stack that is one HTTP request.
// Render your existing HTML invoice to a PDF, Node
const res = await fetch('https://api.sitepdf.com/v1/render', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.SITEPDF_KEY}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
html: renderedInvoiceHtml, // the same template your app shows
format: 'Letter',
margin: 'normal',
archive: true, // keep a dated copy of this invoice
}),
});
const { pdf_url, archive } = await res.json();
Because the render happens in managed Chromium, your CSS, web fonts and any dynamic totals computed in the page all come through exactly as they look in the browser. The PDF generator API page covers this document generation path at volume, the convert HTML to PDF page has the general version. The four bugs that hit rendered invoices in production are listed further down.
Whichever way you get the PDF, keep a dated copy
An invoice is a financial record, and financial records get disputed, audited and requested years later. Whatever produced the PDF, you want to be able to answer "what exactly did we send, and when" without ambiguity. Storing the file is the minimum. Storing it with a trustworthy timestamp of the moment it was produced is what actually settles a dispute.
That is why the render call above uses archive=true. SitePDF keeps a timestamped snapshot of the rendered document, retrievable later by id, so the invoice and its record live together rather than in a bucket you hope nobody touched. If you are fetching from Stripe or QuickBooks instead, replicate the same discipline: download the bytes immediately and store them with the issue date, do not rely on the platform link staying live. The record-keeping angle is covered in more depth on the website archiving page.
What actually breaks when you render invoices
The rendering itself is easy. The failures are boring and specific, and they are all timing or typography. You will meet them in roughly this order.
The font falls back. Your invoice uses a web font from a CDN. The renderer starts printing before the font arrives, so the PDF ships in Times New Roman and finance thinks the invoice is fake. Wait for the fonts to load or embed them, and never trust a third party font host inside a render pipeline. The causes are covered in HTML to PDF fonts not loading.
The total is missing. The line items come from an API call that resolves after first paint, and the renderer prints an empty table. This is the single most common invoice PDF bug, and it is why a serious renderer gives you an explicit wait condition. Tell it to wait for the element that holds the total and it will not write the file until the number is on screen.
The table splits badly. A fourteen item invoice paginates so the last row lands alone on page two, above a subtotal that now looks orphaned from its own table. Print CSS fixes it: break-inside: avoid on rows, a repeating thead, and a real page size instead of whatever the renderer defaults to. The rules are in HTML to PDF page breaks.
The backgrounds vanish. Browsers strip background colors when printing unless told otherwise, so your shaded header row prints white and the invoice looks broken. It is a one line fix and everybody hits it once.
A six point checklist for invoice PDFs
- Render your existing HTML invoice template on the server, at the moment the invoice is issued.
- Wait for the total to be on screen before writing the file.
- Embed or preload fonts, so a CDN does not decide what your invoice looks like.
- Set page size, margins and print CSS explicitly. Never accept renderer defaults for a financial document.
- Store the rendered PDF immutably against the invoice, with a dated capture of what was rendered. A regenerated invoice reflects today's template, tax rates and address, which makes it a reconstruction and not a record.
- Do not generate financial documents in the customer's browser.
If the invoice data lives in a spreadsheet-style database instead of an application, the same rules apply with different tooling. Fixed canvas layout builders break on the first invoice with an unusual number of line items, which is why generating invoice PDFs from Airtable ends up as an HTML templating problem too.
Which approach fits your case
| Your situation | Use this |
|---|---|
| Invoices live in Stripe and the Stripe layout is fine | Fetch invoice_pdf from the invoice object |
| Invoices live in QuickBooks Online | GET the invoice /pdf endpoint with Accept: application/pdf |
| You bill from your own system, or need a branded custom invoice | Render your HTML invoice in managed Chromium via an API |
| The PDF must match the invoice page your app already shows | Render that same HTML template, do not redraw it |
| You need to prove what was sent and when, later | Store the bytes with a dated archive, whatever produced them |
The decision is really "did a platform already make this PDF, or do I have to." If it did, fetch it and store it. If it did not, render the HTML you already own rather than hand building the document, and keep a dated copy either way. Generating the invoice is only half the lifecycle; once it is out the door, getting paid is the other half, and the accounts payable team on the receiving end often runs your invoice straight through accounts payable automation software that reads it and schedules the payment. Designing your invoice so it is clean and machine readable helps both sides.
For the mechanics of rendering, the URL to PDF API and PDF generator API pages have the endpoint details, and the seven tool comparison covers the hosted options with pricing. Invoices are rarely the only document a billing system produces, and once statements, receipts and dunning letters join them, the templating and volume side is covered on the document generation API page.
Written by the team behind SitePDF, an HTML to PDF API that archives every page it renders. The in-browser converter is free to try, and API plans start at $49 a month, half price billed yearly.