Customers in India and Europe now expect to scan and pay directly from an invoice PDF. Yet the tools developers rely on either omit QR codes entirely or gate them behind paid add-ons. QuickBooks Online has fielded user requests for QR codes since February 2020, with staff answering "That is not an option in QBO". A QuickBooks Team member confirmed in January 2022 that no native feature exists and pointed users to third-party apps. By October 2020, some users reported that an auto-generated QR option in print/preview had already vanished. As of September 2026, QuickBooks removed the "Add payment link to PDF" toggle entirely — the QR code appears only on Print, not on downloaded or emailed PDFs. One user complained that month that both the QR option and payment-link setting were missing from their new invoice interface. InvoicePlane users asking for QR codes are directed to a community pull request rather than a built-in feature [1]. Adobe's own guide is a manual workaround: open the PDF in Acrobat online, select Edit, click Image, and upload the QR code by hand [2]. WebToffee sells a paid QR Code Addon for WooCommerce PDF Invoices [3].
Building the QR payload yourself and embedding it into a branded HTML invoice template gives you full control.
The UPI QR payload format is upi://pay?pa=<merchant_upi_id>&pn=<payee_name>&am=<amount>&tn=<transaction_notes> [4]. Omit am to force the customer to enter the amount manually, which is useful for open invoices or tip screens. Percent-encode spaces and special characters to avoid broken scans. A working example:
upi://pay?pa=merchant@upi&pn=Acme%20Design&am=1250.00&tn=Invoice%20ADUQ2189H1-0038
The EPC069-12 standard defines an SEPA QR code payload of exactly 11 lines, maintained by the European Payments Council [5]. The amount field uses the format EURx.xx with a period decimal separator and no thousands separator, e.g. EUR1250.00 [5].
The payload must not exceed 331 bytes in UTF-8. The recipient name is limited to 70 characters and the payment reference to 140 characters. The standard specifies QR error correction level M (15%) [5].
A valid EPC payload:
BCD
001
1
SCT
Acme Design GmbH
DE89370400440532013000
EUR1250.00
Invoice ADUQ2189H1-0038
That empty eleventh line is required. Validate your IBAN with a Mod-97 check digit before embedding — invalid IBANs cause banking app rejection [5].
Any QR code generation service or library that accepts a text payload and returns an image URL will work.
For dynamic invoices, generate the payload per-invoice with the specific amount and reference, then pass the resulting image URL into your template. Your backend might call a QR generation service during invoice creation, or you might use a library like qrcode in Node.js to generate a data URI directly.
MarkupGo templates use Handlebars {{ variable }} placeholder syntax, including {{#each items}} loops for repeating invoice line items [6]. Define a variable like {{ paymentQrUrl }} in your invoice HTML template, then inject the QR image via:
<div class="mt-8 border-t border-gray-200 pt-6">
<p class="text-sm text-gray-500 mb-2">Scan to pay</p>
<img src="{{ paymentQrUrl }}" alt="Scan to pay" class="w-32 h-32">
</div>
Place this inside your branded invoice layout alongside the existing {{#each items}} loop and total calculations. The QR image renders as a standard <img> element during PDF generation, so size it with CSS to fit your design.
POST to https://api.markupgo.com/api/v1/pdf with your x-api-key header, source type template, the template ID, and context data including paymentQrUrl [6]:
fetch("https://api.markupgo.com/api/v1/pdf", {
method: "POST",
headers: {
"x-api-key": process.env.MARKUPGO_API_KEY,
"content-type": "application/json",
},
body: JSON.stringify({
source: {
type: "template",
data: {
id: process.env.INVOICE_TEMPLATE_ID,
context: {
invoice_number: "ADUQ2189H1-0038",
paymentQrUrl: "https://your-qr-service.example/?size=150x150&data=upi%3A%2F%2Fpay%3Fpa%3Dmerchant%40upi%26pn%3DAcme%2520Design%26am%3D1250.00",
items: [
{ item_name: "Design UX and UI", qty: 1, rate: 500, amount: "$500" }
// see Markupgo's API reference for full invoice context
]
}
}
}
})
})
.then(res => res.json())
.then(task => console.log(task.url))
For no-code generation, use https://render.markupgo.com/template/{templateId}.{extension}?{query} [7]. Magic URLs support png, jpeg, webp, and pdf output formats [7]:
https://render.markupgo.com/template/your-template-id.pdf?invoice_number=ADUQ2189H1-0038&paymentQrUrl=https%3A%2F%2Fyour-qr-service.example%2F%3Fsize%3D150x150%26data%3Dyour-encoded-payload
Magic URLs are public — anyone with the URL can generate files and consume your credits [7]. Reusing the same Magic URL within 15 days serves a cached PDF without consuming additional credits; after 15 days the cache clears and credits are consumed again [7].
To avoid exposing the Magic URL directly, use json=true to get a Task object with the generated file URL, or redirect=true for a 302 redirect [7]:
https://render.markupgo.com/template/your-template-id.pdf?...&json=true
Returns a Task object response. The exact structure is shown in MarkupGo's documentation; your code should read the url field from that response to serve the file without exposing the Magic URL itself.
Connect a new Google Sheets row to MarkupGo via Make.com to auto-generate and store branded invoice PDFs. A row with client details and amount triggers payload generation, then a Magic URL render, then saves the PDF to Drive. Magic URLs are suggested for exactly this kind of no-code PDF generation for invoices and reports [7].
Validate your QR payload with a real banking app before shipping to customers. Set up IBAN validation in your invoice generation code to catch EPC rejections early. For high-volume sends, use the API with json=true and store generated PDF URLs in your database rather than regenerating on every request. Review the MarkupGo posts on Stripe invoice generation and HTML invoice templates for the full template setup with items, totals, and branding.