Skip to main content

Power Automate PDF Generation from a SharePoint List: A Handlebars Template plus HTML to PDF Invoice Workflow

· 27 min read
SEO and Content Writer

PDF4me Generate Document Single is a Power Automate action that renders a Handlebars HTML template plus a JSON payload into a finished HTML document, which the paired Convert HTML to PDF action then paginates into A4. A new SharePoint list row fires the flow, Compose assembles the JSON, and Dropbox stores the invoice PDF named after the invoice number. No premium connector, no code.

Every finance team hits the same wall in Power Automate. The native Convert File action requires a premium license and refuses to touch an HTML template. Adobe PDF Services costs. Encodian costs. matthewdevaney's popular workaround skips HTML entirely and locks you into Power Apps. The pattern below is the one nobody in the top ten of the SERP shows end to end: a SharePoint list column set becomes a JSON payload, a real Handlebars template file lives in /Shared Documents/, and two PDF4me actions do the rendering and pagination for the free-tier connector cost.

Handlebars template rendering: PDF4me vs the alternatives

The comparison every Power Automate architect makes before picking a connector for invoice PDFs:

Approach vs PDF4meHandlebars templating?HTML to PDF paginator?Connector tierNotes
PDF4me (this blog)Yes, Generate Document SingleYes, Convert HTML to PDFStandardTwo single-purpose actions, no premium license needed
Adobe PDF ServicesNoYesPremiumCost per user, no template engine, HTML only
EncodianNo native templatingYesPremiumPopular but paid per invocation
matthewdevaney Power Apps routeWord template onlyN/AStandardSkips HTML entirely, locked to Power Apps front-end
Native Convert FileNoWord / Excel only, not HTMLPremiumCannot render an HTML invoice at all
The flow at a glance
1. When an item is created
SharePoint trigger on the Invoices list. Fires per new row, hands every column to the flow as dynamic content.
2. Compose
Builds one JSON payload from the row: invoice, customer, items[], totals, notes. The exact shape the Handlebars template expects.
3. Get file content using path
SharePoint /Shared Documents/invoice_template.html. The Handlebars template lives beside the data, versioned in the same site.
4. PDF - Generate Document (Single)
PDF4me action. Template File Type Html (Handlebars Syntax), Document Data Type Json, Output Type Html.
5. Convert HTML to PDF
PDF4me action. A4, portrait, scale 0.8, 40px margins, print backgrounds Yes.
6. Create file
Dropbox /. File Name Title.pdf, so INV-1005 is saved as INV-1005.pdf.
The short version

A SharePoint Invoices list is the source of truth. A single Handlebars HTML template is stored beside it. On every new row, Compose builds the JSON, PDF4me Generate Document (Single) fills the template, PDF4me Convert HTML to PDF paginates it, and Dropbox saves the finished invoice named after the row's Title. Six actions, all standard-tier connectors, one branded PDF per row.

Why-Based Q&A

Why store the Handlebars template in SharePoint instead of hard-coding the HTML in the flow? The template becomes an editable file that finance or design can update in the browser. Change a logo, tweak the totals row, or add a VAT line, and the very next invoice picks it up. The flow never has to be reopened.

Why two PDF4me actions instead of one? Generate Document (Single) is a template engine, not a paginator. It merges JSON into HTML and returns HTML. Convert HTML to PDF is the paginator that reads that HTML, applies the A4 page size, margins, and background printing, and returns the PDF bytes. Splitting the roles keeps each action single-purpose and lets you preview the rendered HTML before you paginate.

Why Compose in the middle? The Handlebars template is nested (invoice, customer, items array, totals). SharePoint hands you 12 flat columns. Compose is the "assemble JSON" step that shapes the flat columns into the nested payload the template iterates over. Doing it in Compose means Generate Document (Single) sees one clean input rather than 12 dynamic-content pills strewn across its config.

Why Dropbox for the output, not back into SharePoint? Dropbox is the demo storage. Any file connector fits the last step: SharePoint Create file, OneDrive Create file, Google Drive Create file, or SFTP Upload. The Body from Convert HTML to PDF is a plain binary; the destination is a swap, not a rework.


What You'll Get

Input: a SharePoint list called Invoices (columns: Title, InvoiceDate, DueDate, CustomerName, CustomerAddress, CustomerEmail, Currency, Subtotal, TaxRate, TaxAmount, GrandTotal, Notes) plus a single Handlebars template at /Shared Documents/invoice_template.html. Output: one A4 PDF per row in Dropbox, named {Title}.pdf (INV-1005 becomes INV-1005.pdf).


What You Need

  • Power Automate. Open Power Automate. The SharePoint, Dropbox, and PDF4me connectors used below are all standard-tier, no premium plan required.
  • PDF4me API key. Get your API key. Connect it the first time you add a PDF4me action.
  • SharePoint site with a list called Invoices and a Documents library (any name) where the Handlebars template is stored.
  • Dropbox account (or any file destination: SharePoint, OneDrive, Google Drive, SFTP all slot in unchanged).
  • The Handlebars invoice template, ready to upload to /Shared Documents/. invoice_template.html. Every Handlebars path in it matches the mapping table below.
  • Sample signed invoice PDF, exactly what the flow produced for INV-1005. invoice-sample.pdf.

Grab the samples first. Download the Handlebars template and upload it to /Shared Documents/ before you build the flow, so Step 3 has a file to point at. The sample output PDF shows exactly what "success" looks like.


The Flow at a Glance

  1. When an item is created (SharePoint trigger on Invoices list).
  2. Compose the nested JSON payload (invoice / customer / items / totals / notes).
  3. Get file content using path for /Shared Documents/invoice_template.html.
  4. PDF - Generate Document (Single) with the template body plus the JSON, output type Html.
  5. Convert HTML to PDF with A4 portrait, scale 0.8, 40px margins, print backgrounds Yes.
  6. Create file in Dropbox /, file name {Title}.pdf.

Complete flow overview

Power Automate flow overview showing six sequential actions with green success ticks and run durations: SharePoint When an item is created 0.4s, Compose 0s, SharePoint Get file content using path 0.3s, PDF4me PDF - Generate Document Single 0.4s, PDF4me Convert HTML to PDF 11s, and Dropbox Create file 1s

End-to-end run. The 11 second Convert HTML to PDF is the paginator, everything else is under half a second.


Step 1: How do you trigger a Power Automate flow on a new SharePoint invoice?

Flow so far: the flow starts here.

Point the SharePoint trigger at the site and list that holds your invoice rows. Every column becomes dynamic content downstream.

  1. Add SharePoint > When an item is created as the trigger.
  2. Configure:
    • Site Address: pick the SharePoint site (in the sample: PDF4me Sharepoints - https://ynoox1.sharepoint.com/sites/PDF4meSharepoints).
    • List Name: Invoices.
  3. Save and let the trigger detect the list schema. The rows in the screenshot below (INV-1002, INV-1003, INV-1005) show the exact 12 columns the Handlebars template will consume.

The Invoices list

SharePoint Invoices list with three example rows INV-1002 Globex Ltd, INV-1003 Initech Inc, and INV-1005 Initech LLC, showing columns Title, InvoiceJson, InvoiceDate, DueDate, CustomerName, CustomerAddress, CustomerEmail, Currency, Subtotal, TaxRate, TaxAmount, GrandTotal, and Notes

The SharePoint list is the source of truth. Every column here maps into one field of the Handlebars payload.

Trigger configuration

Power Automate SharePoint When an item is created trigger configured with Site Address PDF4me Sharepoints and List Name Invoices, showing the Connected to SharePoint status

Two fields, that is the entire trigger. Everything else comes from the row.

Tip. If your finance team already has the invoices in Excel or Dataverse, keep them there. Swap the trigger for Excel - When a row is added or Dataverse - When a row is added. The rest of the flow does not change.


Step 2: How do you build the Handlebars JSON payload from a SharePoint row?

Flow so far: SharePoint trigger.

Compose shapes the 12 flat SharePoint columns into the nested JSON the Handlebars template iterates over. The template expects invoice, customer, an items array, totals, and a notes string.

  1. Add Compose.
  2. In Inputs, paste the JSON below, then drop the matching SharePoint dynamic-content pill between the quotes of each value so numbers and dates arrive as strings.
{
"invoice": {
"number": "Title",
"date": "InvoiceDate",
"dueDate": "DueDate"
},
"customer": {
"name": "CustomerName",
"address": "CustomerAddress",
"email": "CustomerEmail"
},
"items": [
{ "description": "Item1Description", "quantity": "Item1Qty", "unitPrice": "Item1UnitPrice", "lineTotal": "Item1Amount", "currency": "Currency" },
{ "description": "Item2Description", "quantity": "Item2Qty", "unitPrice": "Item2UnitPrice", "lineTotal": "Item2Amount", "currency": "Currency" },
{ "description": "Item3Description", "quantity": "Item3Qty", "unitPrice": "Item3UnitPrice", "lineTotal": "Item3Amount", "currency": "Currency" },
{ "description": "Item4Description", "quantity": "Item4Qty", "unitPrice": "Item4UnitPrice", "lineTotal": "Item4Amount", "currency": "Currency" },
{ "description": "Item5Description", "quantity": "Item5Qty", "unitPrice": "Item5UnitPrice", "lineTotal": "Item5Amount", "currency": "Currency" }
],
"totals": {
"currency": "Currency",
"subTotal": "Subtotal",
"taxRate": "TaxRate",
"taxAmount": "TaxAmount",
"grandTotal": "GrandTotal"
},
"notes": "Notes"
}

Compose configuration

Power Automate Compose action code view showing a nested JSON payload with invoice (number, date, dueDate), customer (name, address, email), items array of 5 line items (description, quantity, unitPrice, lineTotal, currency), totals (currency, subTotal, taxRate, taxAmount, grandTotal), and notes, every value bound to a SharePoint trigger dynamic content pill

Compose in Code view. Each JSON value is a SharePoint pill between the two quotes, so numbers and dates arrive as strings the Handlebars template can render.

Tip. Keep the items array a fixed size that matches the columns you added to SharePoint (five in this sample). If a row only has three items, leave Item4/Item5 blank in SharePoint and add an {{#if description}} guard around the row in the Handlebars template so empty rows are skipped.

Reference: SharePoint column to Handlebars path

The exact mapping between a SharePoint column and where it lands in the template. Bookmark this table when you extend the schema.

SharePoint columnHandlebars pathTypeUsed in template
Titleinvoice.numberTextInvoice number heading and Dropbox filename
InvoiceDateinvoice.dateDateInvoice header
DueDateinvoice.dueDateDateInvoice header
CustomerNamecustomer.nameTextBill-to block
CustomerAddresscustomer.addressTextBill-to block
CustomerEmailcustomer.emailTextBill-to block
Item{N}Descriptionitems[N-1].descriptionTextLine-item row
Item{N}Qtyitems[N-1].quantityNumberLine-item row
Item{N}UnitPriceitems[N-1].unitPriceNumberLine-item row
Item{N}Amountitems[N-1].lineTotalNumberLine-item row
Currencytotals.currency and each items[].currencyTextCurrency symbol
Subtotaltotals.subTotalNumberTotals block
TaxRatetotals.taxRateNumberTotals block
TaxAmounttotals.taxAmountNumberTotals block
GrandTotaltotals.grandTotalNumberTotals block
NotesnotesTextFooter

Step 3: How do you load the Handlebars template file from SharePoint?

Flow so far: SharePoint trigger plus Compose.

Store the template as a plain .html file in the site's Documents library. The Get file content using path action reads its raw bytes so Generate Document (Single) can use them as the template body.

The template itself

The template is ordinary HTML with inline CSS, plus Handlebars expressions where the data goes. Two constructs do the real work. {{#each items}} repeats a table row per line item, and the {{#if description}} guard inside it skips the blanks left by unused Item4 and Item5 columns.

<tbody>
{{#each items}}
{{#if description}}
<tr>
<td>{{description}}</td>
<td class="num">{{quantity}}</td>
<td class="num">{{currency}}{{unitPrice}}</td>
<td class="num">{{currency}}{{lineTotal}}</td>
</tr>
{{/if}}
{{/each}}
</tbody>

Everything else is a direct substitution: {{invoice.number}} in the header, the {{customer.*}} block for bill-to, {{totals.*}} in the totals table, and {{notes}} in the footer.

Download the template. Upload it to /Shared Documents/ as invoice_template.html, then edit the seller name, address, and VAT number at the top. Those are deliberately static, so they are the only lines you need to touch before your first run.

  1. Add SharePoint > Get file content using path.
  2. Configure:
    • Site Address: same site as the trigger.
    • File Path: /Shared Documents/invoice_template.html.
    • Infer content type: Yes (leave the default).

Get file content using path

Power Automate SharePoint Get file content using path action with Site Address PDF4me Sharepoints, File Path /Shared Documents/invoice_template.html, and Infer content type Yes

The template lives in /Shared Documents/ and is fetched by absolute path. Version history is automatic because it is just a SharePoint file.

Tip. If your template lives in OneDrive or Dropbox instead, swap this action for the storage's equivalent Get file content. The Body output of any of them is what the next step feeds to Template File Data.


Step 4: How does PDF - Generate Document (Single) fill the Handlebars template?

Flow so far: SharePoint trigger plus Compose plus Get file content using path.

Generate Document (Single) is the template engine. It reads the Handlebars source ({{invoice.number}}, {{#each items}}...{{/each}}), substitutes values from the JSON payload, and returns rendered HTML. It does not paginate. That is the next step's job.

  1. Add PDF4me PDF > PDF - Generate Document (Single).
  2. Configure:
    • Template File Type: Html (Handlebars Syntax).
    • Template File Name: invoice_template.html.
    • Template File Data: dynamic content, Body from the SharePoint Get file content step.
    • Document Data Type: Json.
    • Document Data Text: dynamic content, Body from the Compose step.
    • Output Type: Html.
    • Keep Pdf template Editable: No.

Generate Document (Single) configuration

PDF4me PDF - Generate Document (Single) action with Template File Type Html (Handlebars Syntax), Template File Name invoice_template.html, Template File Data mapped from SharePoint Body, Document Data Type Json, Document Data Text mapped from Compose Body, Output Type Html, Keep Pdf template Editable No, and Connected to PDF4me PDF status

Output Type is Html, not Pdf. Generate Document (Single) hands off the rendered HTML to the next step so pagination stays a separate, testable concern.

Tip. Generate Document (Single) also supports Word and PDF templates. If the design team hands you a .docx invoice mockup, set Template File Type to Word and change Output Type to Pdf to skip the Convert step entirely. The Handlebars route wins when you want CSS control and browser-preview iteration.


Step 5: How do you paginate the rendered HTML into an A4 PDF?

Flow so far: SharePoint trigger plus Compose plus Get file content using path plus PDF - Generate Document (Single).

Convert HTML to PDF is the pagination engine. It reads the HTML produced by Generate Document (Single), applies page size and margins, and returns the PDF bytes.

  1. Add PDF4me PDF > Convert HTML to PDF.
  2. Configure:
    • File Content: dynamic content, Body from the Generate Document (Single) step.
    • HTML File Name: invoice.html.
    • Page Layout: Portrait.
    • Page Size: A4.
    • Scale: 0.8 (fits the 5-item invoice on one page).
    • Top / Bottom / Left / Right Margin: 40px each.
    • Print Background: Yes (renders the totals block's background colour).

Convert HTML to PDF configuration

PDF4me Convert HTML to PDF action with File Content mapped from Generate Document Body, HTML File Name invoice.html, Page Layout Portrait, Page Size A4, Scale 0.8, Top Bottom Left Right Margins all 40px, and Print Background Yes

Scale 0.8 keeps a five-line invoice on a single A4 page. Bump it to 0.9 or 1.0 if you have fewer items and want a larger font.

Tip. Print Background: Yes is the setting that finally makes coloured <td> cells and CSS gradients appear. Browsers strip background colours from print by default. If your totals row looks white in the PDF, this is why.


Step 6: How do you save the invoice PDF to Dropbox with a predictable name?

Flow so far: SharePoint trigger plus Compose plus Get file content using path plus PDF - Generate Document (Single) plus Convert HTML to PDF.

The final step drops the PDF into a Dropbox folder with a name tied to the invoice number.

  1. Add Dropbox > Create file.
  2. Configure:
    • Folder Path: / (or a subfolder like /invoices/).
    • File Name: dynamic content, Title from the SharePoint trigger, followed by the literal string .pdf. INV-1005 becomes INV-1005.pdf.
    • File Content: dynamic content, Body from the Convert HTML to PDF step.

Create file configuration

Power Automate Dropbox Create file action with Folder Path /, File Name built from SharePoint Title trigger field followed by .pdf, and File Content mapped from Convert HTML to PDF Body, showing Connected to Dropbox status

Naming the file after the invoice number means the Dropbox folder becomes a searchable, deduplicated invoice archive automatically.

Tip. If two rows can ever share the same Title, add a _ and a timestamp: concat(triggerBody()?['Title'], '_', ticks(utcNow()), '.pdf'). Otherwise Dropbox silently overwrites the previous file with the same name.


Run the Flow and Verify

  1. Save the flow at the top right.
  2. Add a new row to the Invoices SharePoint list. Set Title to something recognisable (INV-1005) and fill every column so the template has real data.
  3. Open the flow's Run history and pick the latest run. Every card should be green, similar to the flow overview screenshot. The Convert HTML to PDF card is the slowest (about 11 seconds) because that is where pagination happens.
  4. Open Dropbox and confirm INV-1005.pdf (or your Title) is in the root. Download it, open it, and compare to the sample.

What did you actually build? A SharePoint-native invoice generator with an editable HTML template, all in six standard-tier connector actions. The same pattern (row plus template plus render plus paginate plus store) works for quotes, delivery notes, purchase orders, warranty certificates, or any per-row branded PDF. Swap SharePoint for Dataverse or Excel, swap Dropbox for OneDrive, keep the two PDF4me actions.


Common Variations You Can Add Without Rebuilding

Email the invoice to the customer
Insert an Outlook Send an email (V2) after Create file. Attach the Convert HTML to PDF Body and address it to the SharePoint CustomerEmail column.
Stamp a signature on page 1
Add a PDF - Sign action after Convert HTML to PDF. Overlay a PNG signature from Dropbox at bottom-right of page 1 for authorised invoices.
Push a copy back to SharePoint
Add a second SharePoint Create file after Dropbox and drop the PDF into Shared Documents/Signed Invoices/ so it is preserved beside the source list.
Convert vs Adobe / Encodian (comparison)
Adobe PDF Services and Encodian both offer HTML to PDF connectors but require premium licenses per user. PDF4me runs on the standard connector tier and pairs Generate Document (Single) for templating, which Adobe's flow does not include.

Common questions

How to create a pdf using power automate from a sharepoint list item?

Use SharePoint's When an item is created as the trigger, a Compose action to shape the row's flat columns into a nested JSON payload, a Get file content using path action to load your HTML template from /Shared Documents/, PDF4me Generate Document (Single) to merge the JSON into the template, and PDF4me Convert HTML to PDF to paginate the result. Save the output to any file connector (Dropbox, OneDrive, SharePoint). Every action in that chain is on the standard connector tier, so you do not need a Power Automate Premium license.

Can power automate generate a pdf?

Yes. Native Power Automate cannot render a PDF on its own from an HTML template, but the PDF4me connector adds the two actions that make it possible: Generate Document (Single) for template rendering and Convert HTML to PDF for pagination. Both are standard-tier and free to install. Together they turn any SharePoint / Dataverse / Excel row into a branded PDF using an editable HTML template stored beside the data.

How to create pdf from html in power automate?

Add the PDF4me Convert HTML to PDF action anywhere the flow has HTML in scope (a Compose output, a Get file content Body, a Compose expression, a webhook payload). Configure the page size (A4), layout (Portrait), margins (40px), and set Print Background: Yes so CSS backgrounds are preserved. The action's Body output is the PDF binary you feed to your storage action. This is the same action used in Step 5 above.

Can power automate convert html to pdf without premium?

Yes. The PDF4me connector's Convert HTML to PDF action is on the standard connector tier, meaning you can install it and use it on any Power Automate plan without the Premium license upgrade that the native Convert File and Adobe PDF Services connectors require. You still need a PDF4me API key (free tier available), which you paste in when you add the action the first time.

How to generate pdf from a template in power automate?

Use PDF4me Generate Document (Single) with Template File Type: Html (Handlebars Syntax) (for HTML templates) or Word (for .docx templates). Feed the template bytes into Template File Data and a JSON payload into Document Data Text. Set Output Type: Html if you need to paginate afterwards (as in this blog), or Pdf to get a PDF back in one step. The action supports the full Handlebars syntax including {{#each}} and {{#if}} for line items and conditional blocks.


Troubleshooting

Handlebars renders {{invoice.number}} literally in the PDF

The template placeholder was not substituted, which means Document Data Text was empty or malformed JSON. Open the Compose step's Outputs in the run history and confirm it is a valid JSON object with the exact key path Handlebars is looking for (case-sensitive).

Totals row appears white in the PDF but coloured in the browser preview

Set Print Background: Yes on Convert HTML to PDF. Chromium's print engine strips background colours from <td> and <div> by default; this switch re-enables them.

Invoice runs onto two pages, second page shows just one line

Lower the Scale on Convert HTML to PDF from 0.8 to 0.7. Alternatively, add page-break-inside: avoid on the <table> in the template, so pagination breaks between rows and not within them.

Dropbox Create file silently overwrites an earlier invoice

Two rows shared the same Title. Change the File Name expression to concat(triggerBody()?['Title'], '_', ticks(utcNow()), '.pdf') so every run produces a unique filename.


Next Steps

The same six-step pattern (row plus template plus render plus paginate plus name plus store) handles any per-row branded PDF you can describe in HTML.