Bill
Custom Attachments

Invoice Attachments

Attach supporting documents to invoices for complete record keeping and audit trails


Invoice attachments enable you to store supporting files directly with your invoices—such as receipts, contracts, purchase orders, delivery confirmations, or detailed breakdowns. By attaching files to invoices, you maintain complete documentation, simplify audits and compliance, and provide customers with all relevant information in one place. Attachments are stored securely and can be accessed programmatically or shared via invoice payment links.

Common Use Cases

  • Attach vendor receipts for expense reimbursement invoices
  • Include signed contracts or service agreements with invoices
  • Attach customer purchase order documents for reference

Prerequisites

Before working with invoice attachments, ensure you have:


Uploading Invoice Attachments


Create invoices with attachments using base64-encoded data URIs.

import payload
 
pl = payload.Session('secret_key_3bW9...', api_version='v2')
 
import base64
 
 
# Helper function to convert file to base64 data URI
def file_to_data_uri(file_path, mime_type):
    with open(file_path, 'rb') as file:
        base64_file = base64.b64encode(file.read()).decode('utf-8')
        return f"data:{mime_type};base64,{base64_file}"
 
 
# Create an invoice with inline attachment
 
# Convert file to base64 data URI
file_data_uri = file_to_data_uri('./receipt.pdf', 'application/pdf')
 
invoice = pl.Invoice.create(
    due_date='2024-03-01',
    description='Consulting services',
    payer={'account_id': 'acct_customer123'},
    biller={'account_id': 'acct_merchant456'},
    items=[
        {
            'type': 'line_item',
            'description': 'Consulting services',
            'line_item': {'value': 1500.00, 'qty': 1},
        }
    ],
    attachments=[
        {
            'file': {'data_uri': file_data_uri},
            'filename': 'receipt.pdf',
            'description': 'Payment receipt from vendor',
        }
    ],
)
 
print(f'Invoice created: {invoice.id}')
print(f'Invoice has {len(invoice.attachments)} attachment(s)')
print(f'Attachment: {invoice.attachments[0].filename}')
print(f'Download URL: {invoice.attachments[0].url}')

File encoding requirements:

  • Files must be base64-encoded as data URIs
  • Format: data:{mime_type};base64,{base64_content}
  • Example: data:application/pdf;base64,JVBERi0xLjQKJ...
  • Supported for all file types

What happens when creating invoices with attachments:

  1. Invoice is created with attached files
  2. File content is uploaded and stored securely
  3. Attachment metadata is created (filename, type, size)
  4. Attachments are available immediately via the invoice for presentment

Retrieving Invoice Attachments


Access attachments through the invoice object or query attachments directly.

import payload
 
pl = payload.Session("secret_key_3bW9...", api_version="v2")
 
# List all attachments for an invoice
 
invoice = pl.Invoice.get("inv_abc123")
 
print(f"Invoice {invoice.id} has {len(invoice.attachments)} attachment(s):\n")
print(invoice.attachments)
for attachment in invoice.attachments:
    print(f"Attachment: {attachment.id}")
    print(f"  Filename: {attachment.filename}")
    print(f"  Description: {attachment.description}")
    print(f"  Type: {attachment.type}")
    print(f"  Size: {attachment.size} bytes")
    print(f"  Download URL: {attachment.url}")
    print(f"  Category: {attachment.attrs.get('category')}")
    print(f"  Uploaded: {attachment.created_at}\n")
 
# Query attachments directly across all invoices
all_attachments = pl.InvoiceAttachment.filter_by(
    q='attrs[category] == "receipt"', order_by="desc(created_at)", limit=10
).all()
 
print(f"Found {len(all_attachments)} receipt attachments across all invoices")

Query attachments across invoices

Search for specific attachments across all invoices:

# Find all PDF receipts
receipts = pl.InvoiceAttachment.filter_by(
    q='type == "application/pdf" && attrs[category] == "receipt"',
    order_by="desc(created_at)"
).all()
 
print(f"Found {len(receipts)} PDF receipts")

Download attachment files

Use the url field to download attachment content:

import os
import requests
 
attachment = pl.InvoiceAttachment.get("file_abc123")
 
print(f"Download file from: {attachment.url}")
 
response = requests.get(attachment.url, headers={
    "Authorization": f"Bearer {os.environ.get('PAYLOAD_API_KEY')}"
})
 
with open(f"./{attachment.filename}", "wb") as f:
    f.write(response.content)
 
print(f"File saved as {attachment.filename}")

Managing Attachments


Remove or replace invoice attachments.

Delete attachments

import payload
 
pl = payload.Session("secret_key_3bW9...", api_version="v2")
 
# Delete an attachment from an invoice
 
attachment = pl.InvoiceAttachment.get("file_abc123")
 
print("Deleting attachment:")
print(f"  ID: {attachment.id}")
print(f"  Filename: {attachment.filename}")
print(f"  Invoice: {attachment.invoice_id}")
 
# Delete the attachment
attachment.delete()
 
print("Attachment deleted successfully")
 
# Verify attachment removed from invoice
invoice = pl.Invoice.get(attachment.invoice_id)
print(f"Invoice now has {len(invoice.attachments)} attachment(s)")

Replace attachments

To replace a file, delete the old attachment and upload a new one:

import base64
 
def file_to_data_uri(file_path, mime_type):
    with open(file_path, "rb") as f:
        base64_file = base64.b64encode(f.read()).decode("utf-8")
    return f"data:{mime_type};base64,{base64_file}"
 
attachment = pl.InvoiceAttachment.get("file_old123")
attachment.delete()
 
file_data_uri = file_to_data_uri("./receipt_v2.pdf", "application/pdf")
 
pl.InvoiceAttachment.create(
    invoice_id="inv_abc123",
    file={"data_uri": file_data_uri},
    filename="receipt_v2.pdf",
    description="Updated receipt - corrected amount",
    type="pdf",
    attrs={
        "version": 2,
        "replaces": "file_old123",
        "reason": "Amount correction"
    }
)
 
print("Attachment replaced")

Schema Reference


Fields relevant to invoice attachments:

InvoiceAttachment Fields

id
stringRead-only
Unique identifier for the resource. Automatically generated upon creation and cannot be modified. (ID prefix: file)
Pattern: ^file_[A-Za-z0-9]+$
invoice_id ID of Invoice
string
The unique identifier of the invoice that this file is attached to. Links the attachment to its parent invoice. Attachments can be used to include supporting documents like receipts, contracts, or detailed breakdowns with the invoice. (ID prefix: None)
Pattern: ^None_[A-Za-z0-9]+$
filename
string
The original filename of the uploaded file as provided by the user. This preserves the user-friendly name for display purposes and reference, while the system uses a separate internal filename for storage.
Max length: 52
description
string
Optional free-form text description providing additional context or notes about the file. This can be used to store information about the file's purpose, contents, or any other relevant details for reference.
Max length: 52
type
string
The file type extension of the uploaded file. Possible values include: svg, pdf, png, jpg, jpeg, and docx. This is automatically detected from the uploaded file and is used to validate allowed file types and apply appropriate security checks.
Max length: 12
size
integer (int64)Read-only
The size of the uploaded file in bytes. This field is automatically calculated when the file is uploaded and stored, and is read-only. It can be used for display purposes or to enforce storage quotas.
url
stringRead-only
The publicly accessible URL where the file can be retrieved. This URL is automatically generated based on the internal filename and the configured server hostname. The URL will use HTTPS in production environments and HTTP otherwise.
Max length: 64
attrs
object
Custom attributes for extending the resource with additional key-value pairs. Maximum length is 255 characters when serialized.

Invoice Attachment Reference

array
Collection of all file attachments associated with this invoice. May include PDFs, images, receipts, or other supporting documentation. Expanded by default to show all attached files.

Next Steps

Enhance your invoice management with additional features


Manage Invoice Workflow

Build detailed invoices with line items using Creating Invoices, track invoice lifecycle and status changes with Invoice Statuses, and automate recurring invoice generation with Billing Schedules.

Process Invoice Payments

Accept payments against invoices with Payment API, send payment links to customers with Payment Requests, and enable autopay for recurring billing with Automatic Payments.

Track and Report

Monitor attachment upload events with Webhook Events, generate comprehensive invoice reports with Reporting Overview, and analyze payment data with Transaction Reports.


Related articles