Skip to main content

Overview

A Peppol invoice is a UBL XML file. A file that the receiver must get (for example a PDF copy of the invoice or a timesheet) must be embedded in that UBL. There are three methods to add a file to a document. Only two of them put the file in the UBL.
This page is about files that go out with a document. To use a PDF as the input from which a document is created, see Create documents from PDF.

Add attachments when you create the document

Add an attachments array to the body of POST /api/documents/. The API embeds each file in the UBL as an AdditionalDocumentReference and stores it with the document.
string
required
File name with extension, for example timesheet-2026-09.pdf. The receiver sees this name.
string
default:"application/pdf"
MIME type of the file. See the permitted types below.
string
File content, base64 encoded. Always supply this field when you create a document.
integer
default:"0"
Optional. The API calculates the stored size from the decoded file_data.
Before you run the sample, replace the vendor fields with the data of your company. The API rejects a document if the Peppol ID of the vendor is not one of the peppol_ids of your company. The API returns 201 Created with the document in the DRAFT state. The response below shows only the fields that are related to attachments.

Permitted file types

Peppol rule BR-CL-24 permits only these MIME types for a file that is embedded in the UBL: If file_type is not one of these values, the API uses the extension of file_name (.pdf, .png, .jpg, .jpeg, .csv, .xlsx, .ods) to find the MIME type that it writes to the UBL. Give each file a correct extension.

File size

The API does not publish a size limit for the files in attachments[]. Base64 makes the request body approximately one third larger than the file, and the receiving Access Point must accept the full UBL. Keep attachments small, and send large supporting files through a different channel.
The limits of 5 MB for each file and 25 MB for each batch apply to the PDF conversion endpoint only. See Create documents from PDF.
Validation is not a separate mandatory call. POST /api/documents/ rejects a payload that does not pass the same rules. Use POST /api/validate/json while you develop, because it returns all rule failures and the generated UBL.

Let the platform make the PDF

Add the query parameter construct_pdf=true to POST /api/documents/. The API then does these steps:
1

Generate the UBL

The API converts the JSON body to UBL and validates it.
2

Render the PDF

The API makes a PDF from that UBL.
3

Embed the PDF

The API adds the PDF to the attachments of the document, generates the UBL again with the PDF embedded, and validates the result.
The receiver gets a UBL that contains a readable PDF copy of the invoice. If the body also has an attachments array, the generated PDF is added after those files, and the UBL contains all of them.
boolean
default:"false"
If true, the API generates a PDF from the document, stores it as an attachment and embeds it in the UBL.
The samples read the invoice JSON from a file invoice.json. Save this payload in that file:
Invoice
Replace the vendor fields with the data of your company. The API rejects a document if the Peppol ID of the vendor is not one of the peppol_ids of your company.

File name of the generated PDF

  • The name is <invoice_id>-generated.pdf.
  • Each character of invoice_id that is not a letter, a digit, -, _ or . becomes -. For example, INV/2026 001 gives INV-2026-001-generated.pdf.
  • If the document has no invoice_id, the name is a random UUID followed by -generated.pdf.

Errors

The command-line tool has the same option: peppol document create json invoice.json --construct-pdf.

Deprecated upload endpoint

POST /api/documents/{document_id}/attachments is deprecated. A file that you upload with this endpoint is stored with the document, but it is not added to the UBL. The receiver does not get it. To send a file to the receiver, put it in attachments[] when you create the document, or use construct_pdf=true.
Existing integrations that use this endpoint send a multipart/form-data request with one file in the form field file:
cURL

List, download and delete attachments

These calls work for documents that you created and for documents that you received.

List the attachments of a document

cURL
If the document has no attachments, this call returns 404 with the detail Document attachments not found. It does not return an empty array. Treat this response as an empty list.
For a sample in five languages that lists and downloads all attachments, see Download the attachments and the PDF.

Download one attachment

Get the attachment to receive a file_url. This is a signed URL that is valid for 1 hour. Download the file from that URL with a plain GET request, without the Authorization header.
cURL
cURL
Do not store file_url. Request a new URL each time that you need the file.

Delete an attachment

You can delete an attachment only while the document is in the DRAFT or FAILED state.
cURL
This call removes the stored attachment only. It does not generate the UBL again. To send a document without a file that is embedded in its UBL, delete the document and create it again without that file.
For the states of a document, see Document lifecycle and delivery tracking.

Download the UBL

GET /api/documents/{document_id}/ubl returns the metadata of the UBL file of a document and a signed URL from which you can download the XML. Use it to see what the receiver gets, or to archive the UBL of a received document.
cURL
Fields that have no value are not in the response. The call returns 404 if the document has no UBL. Do not store signed_url. For a download sample in five languages, see Download the original UBL.

Uploaded UBL and received documents

You do not add attachments separately in these two cases. The files are already in the UBL.
  • Documents that you create from UBL. When you upload a UBL file with POST /api/documents/ubl, the API extracts each embedded file and stores it as an attachment of the document. The UBL is not changed. See Send UBL documents.
  • Received documents. The API extracts each file that the sender embedded and stores it as an attachment. If the received UBL contains no PDF, the API generates a PDF from the UBL and stores it as an attachment with the name <document_id>.pdf. Thus a received document usually has a PDF that you can show to a person. See Receive documents.
Use the list and download calls above to get these files.

Test with a sandbox company

Develop and test with a sandbox company. A sandbox company runs in test mode: the API sends each document as UBL XML to the contact email address of the company, and nothing goes to the Peppol network. The API host and the endpoints are the same as for a production company. See Test mode and sandbox companies.
Create a document with attachments[] or construct_pdf=true in a sandbox company, send it, and open the XML from the email. Each file is in an AdditionalDocumentReference element as base64 content.

Next Steps

Create e-invoices

Build the invoice body to which you add attachments.

Create documents from PDF

Use a PDF as the input for a new document.

Receive documents

Read received invoices and their attachments.

Validation during development

Examine the generated UBL before you create a document.