Introduction

Billing consolidation is a workflow that combines multiple financial documents into a single PDF using GroupDocs.Merger for Python. Finance teams often need to send an invoice together with delivery notes, service reports, and warranty terms, but manually stitching files creates errors and wastes time. GroupDocs.Merger automates this process, ensuring every attachment is correctly ordered, optionally secured, and delivered as one clean PDF.

In this tutorial you will see how to:

  • Merge a plain‑PDF invoice with any number of supporting files.
  • Handle mixed formats such as JPG images and DOCX contracts.
  • Open a password‑protected invoice, add attachments, and re‑apply encryption.
  • Include only selected pages from large attachments to keep the final bundle compact.

I ran into this exact scenario last quarter when our accounting system generated a password‑protected invoice and the legal team added a multi‑page warranty DOCX. The code below solved it in under five minutes.

When does it make sense to merge a password‑protected invoice with other documents?

Many enterprises encrypt invoices at rest to meet compliance requirements. When the invoice needs to be sent to a customer along with unprotected attachments (receipts, terms, images), the original password must be removed for merging and then reapplied to the final bundle. GroupDocs.Merger lets you supply the unlock password via LoadOptions, join the extra files, and finally protect the merged PDF with AddPasswordOptions. This keeps the confidentiality posture intact while delivering a single, easy‑to‑open document.

Prerequisites

  • Python 3.8+ (via .NET bridge)
  • GroupDocs.Merger for Python – install with:
pip install groupdocs-merger
  • A lead invoice PDF (invoice.pdf) and a list of attachment file paths.
  • (Optional) Passwords for the source invoice and the output PDF.

Step 1: Basic Consolidation of PDF Attachments

The simplest case is merging a PDF invoice with other PDFs, images, or Word files. The API automatically converts non‑PDF inputs to PDF before joining.

import groupdocs_merger as gm

# Paths to source files
invoice = "invoice.pdf"
attachments = ["delivery_note.pdf", "service_report.pdf"]
output = "billing_package.pdf"

with gm.Merger(invoice) as merger:
    for path in attachments:
        merger.join(path)  # Normalises each file to PDF and appends it
    merger.save(output)

Key points:

  • gm.Merger is instantiated with the host document (the invoice).
  • join() accepts any supported format; the library handles conversion.
  • save() writes the merged PDF to the specified path.

Step 2: Consolidating Mixed‑Format Attachments

Real‑world billing packets often contain scanned images (JPG) and legal contracts (DOCX). The same code works because GroupDocs.Merger normalises every attachment to PDF on the fly.

attachments = ["receipt.jpg", "warranty_terms.docx", "extra_clause.pdf"]
output = "billing_mixed.pdf"

with gm.Merger(invoice) as merger:
    for path in attachments:
        merger.join(path)  # JPG and DOCX are converted to PDF automatically
    merger.save(output)

Why it matters: Converting everything to PDF eliminates the need for the recipient to juggle multiple viewers, delivering a seamless experience.

Step 3: Handling Password‑Protected Invoices

If the invoice is encrypted, provide the password via LoadOptions. After merging, you can re‑apply a password to the final PDF using AddPasswordOptions.

import io

invoice_password = "Inv$2026"
output_password = "Bill$2026"

load_options = gm.domain.options.LoadOptions(invoice_password)
buffer = io.BytesIO()

# Open the protected invoice, join attachments, write to memory buffer
with gm.Merger(invoice, load_options) as merger:
    for path in attachments:
        merger.join(path)
    merger.save(buffer)

# Re‑secure the merged document
add_pwd = gm.domain.options.AddPasswordOptions(output_password)
buffer.seek(0)
with gm.Merger(buffer) as merger:
    merger.add_password(add_pwd)
    merger.save(output)

Key points:

  • LoadOptions unlocks the source PDF.
  • The merged result is first written to an in‑memory stream (BytesIO).
  • AddPasswordOptions applies a new password to the final file.

Step 4: Selecting Specific Pages from Attachments

Sometimes only a subset of an attachment is relevant (e.g., the first two pages of a lengthy service report). Use PageJoinOptions to specify an inclusive 1‑based range.

page_picks = [
    ("service_report.pdf", 1, 2),   # Include pages 1‑2 only
    ("terms_and_conditions.pdf", 3, 3)  # Include only page 3
]
output = "billing_selected_pages.pdf"

with gm.Merger(invoice) as merger:
    for path, first, last in page_picks:
        options = gm.domain.options.PageJoinOptions(first, last)
        merger.join(path, options)
    merger.save(output)

Result: The final PDF contains the invoice plus only the chosen pages, keeping the bundle lightweight.

Best Practices & Tips

  • Performance: For large batches, enable only the options you need (e.g., avoid unnecessary format conversion).
  • Memory Management: Always use the with statement to ensure the Merger releases resources promptly.
  • Security: Re‑apply encryption after merging to maintain the confidentiality of the original invoice.
  • File Limits: GroupDocs.Merger supports PDFs up to 2 GB; larger files may require splitting before merging.

Conclusion

GroupDocs.Merger for Python provides a straightforward API to turn a scattered set of billing documents into a single, professional PDF package. Whether you are dealing with plain PDFs, mixed media, password‑protected invoices, or need to trim attachments to essential pages, the library handles the heavy lifting in just a few lines of code.

Next steps:

  • Explore the full list of supported formats in the documentation.
  • Learn how to add watermarks or digital signatures to the merged PDF (API reference).
  • Check out the sample projects on GitHub for more advanced scenarios (Examples Repo).

Additional Resources