Skip to main content

Overview

When a supplier sends an invoice or a credit note to your Peppol ID, e-invoice.be receives the document, stores it, and puts it in the inbox of your company. This guide shows how to find new documents, how to read their data, and how to download the original UBL file, the PDF and the other attachments. A received document has direction: "INBOUND" and state: "RECEIVED".

Prerequisites

  • An API key for the company that receives the documents. See Authentication.
  • A production company must be registered as a receiver on the Peppol network. Without this registration, senders cannot find your Peppol ID and no document arrives.
  • A sandbox company does not receive documents from the Peppol network. Use Simulate inbound to put documents in its inbox. See Test with a sandbox company.
Resellers: a send-only tenant has no Peppol registration, thus its inbox stays empty. See Send-only tenants in the Admin API guide.

How a document arrives

1

e-invoice.be receives the document

The access point receives the Peppol message and finds the company from the receiver Peppol ID.
2

The UBL and its attachments are stored

The original UBL XML is stored. Each file that the sender embedded in the UBL is extracted and stored as an attachment of the document.
3

A PDF is made if the sender did not supply one

If the UBL contains no PDF attachment, e-invoice.be generates a PDF from the UBL and adds it as an attachment with the file name {document_id}.pdf.
4

The document goes to the RECEIVED state

The document data (parties, totals, line items) is available as JSON, and the document is in the inbox.
5

The webhook is sent

Each webhook of the company that subscribes to document.received gets an event with the document_id.

Find new documents

There are two methods to find new documents: webhooks and polling. Webhooks are the recommended method. Polling is a good safety net in addition to webhooks.
The API has no “mark as processed” endpoint and no “unread” filter. A document stays in the inbox after you read it. Your system must record which documents it has processed. See Prevent double processing.
Create a webhook that subscribes to document.received. e-invoice.be calls your URL when a document is in the RECEIVED state. Webhooks gives the setup procedure and the signature verification.
The event contains only the document_id. Use this ID to get the document.
The event document.received.failed tells you that e-invoice.be could not process an incoming document. The data object has the same shape. Such a document is not in the RECEIVED state, thus GET /api/inbox/ does not list it.

Polling

Call GET /api/inbox/ at a fixed interval. The default sort is created_at in descending order, thus the newest documents are on the first page.
The response is one page of documents. Each item has the same shape as the response of GET /api/documents/{document_id}.
Read the subsequent page while has_next_page is true.

Prevent double processing

Because the API does not record what you have processed, keep this record in your own system. Use one of these patterns, or the two together.
Store the id of each document after you process it. Before you process a document, look for its id in your store and skip the document if the id is there.This pattern is correct for webhooks and for polling. Use it in each webhook handler, so that a repeated event does not process the same document twice.
Store the created_at value and the id of the newest document that you processed. At each poll, read the inbox with sort_by=created_at and sort_order=desc, page by page, and stop when you find a document whose created_at is not later than the stored value. Process the documents that you collected from the oldest to the newest, then store the new cursor.date_from and date_to filter on the issue date of the invoice (invoice_date), not on the time of receipt. Do not use them as a cursor: a supplier can send an invoice with an issue date in the past.
These programs read the inbox from the newest document to the stored cursor, download the UBL of each new document, and then move the cursor. The cursor is in a local JSON file; use your database in a production system.

Get the document

GET /api/documents/{document_id} returns the data of the document as JSON. This is the same endpoint and the same schema as for the documents that you send. See the Document schema.
The response does not contain fields that have no value. Read optional fields defensively. These fields are the most important for a received document:
A received self-billing document has the type SELFBILLING_INVOICE or SELFBILLING_CREDIT_NOTE. In a self-billing document, the buyer issues the invoice in the name of the supplier, thus your company is the vendor on the document and not the customer. See Self-billing and debit notes.

Download the original UBL

The JSON data is a conversion of the UBL. Keep the original UBL XML for your archive: it is the legal document that the sender transmitted. GET /api/documents/{document_id}/ubl returns the metadata of the UBL file and a signed URL for the download.
validated_at is present when the UBL was validated. The signed_url is valid for 1 hour. For the description of each field, see Download the UBL.
Do not store signed_url. It stops working after 1 hour. Store the document_id, and request a new URL each time that you need the file. The URL contains its own signature, thus do not add your API key to the download request.

Download the attachments and the PDF

A received document can have attachments: the PDF of the invoice and the other files that the sender embedded in the UBL (for example a timesheet or a delivery note). If the sender embedded no PDF, the list contains the PDF that e-invoice.be generated, with the file name {document_id}.pdf.

List the attachments

GET /api/documents/{document_id}/attachments returns all attachments of the document. Each item has a file_url that you can download immediately.
This endpoint returns 404 Not Found with "detail": "Document attachments not found" when the document has no attachments. Treat this response as an empty list.

Get one attachment

GET /api/documents/{document_id}/attachments/{attachment_id} returns one attachment with a new file_url. Use this call when you stored the attachment ID and you need the file again later.
If the attachment does not exist, the endpoint returns 404 Not Found with "detail": "Document attachment not found". See also Download one attachment.
file_url is valid for 1 hour. Do not store it and do not show it to your users as a permanent link. Store the document_id and the attachment id, and request a new URL when you need the file.
To find the PDF of the invoice, select the attachment with file_type equal to application/pdf. A sender can embed more than one PDF; in that case use file_name to identify the correct file. See Attachments and PDF for the permitted file types and for the procedure to add attachments to the documents that you send.

Filter the inbox

GET /api/inbox/ returns the documents with direction: "INBOUND" and state: "RECEIVED". It accepts the parameters in this table. All parameters are optional, and you can combine them. See List, filter and manage documents for the full description of each parameter. These rules are important for received documents:
  • date_from and date_to filter on the issue date of the invoice (invoice_date), not on the time of receipt.
  • sender finds a text in vendor_name, vendor_email, vendor_tax_id or vendor_company_id.
  • Received documents do not get the type DEBIT_NOTE, thus type=DEBIT_NOTE returns an empty list.
Example: all credit notes from E-INVOICE BV with an issue date in October 2026, the oldest first.
cURL
The response has the same paginated shape as the response in Polling.

Shortcut endpoints

Two endpoints return one document type only. They accept page, page_size, sort_by and sort_order, and return the same paginated response. They do not accept sender, date_from, date_to or search; use GET /api/inbox/ with the type parameter when you need these filters.

Test with a sandbox company

A sandbox company gets no documents from the Peppol network. Use Simulate inbound to put a document in its inbox:
1

Open the inbox of the sandbox company

In app.e-invoice.be, select your sandbox company and open Inbox.
2

Simulate an inbound document

Click Simulate inbound. Select the built-in sample invoice, or upload your own UBL XML file.
3

Run your integration

The document is in the RECEIVED state, GET /api/inbox/ lists it, and the document.received webhooks of the company are sent. All samples on this page operate on this document with the API key of the sandbox company.
A document that you send to your own company does not come into the inbox. In a sandbox company, a send goes to the contact email address of the company and not to Peppol, thus the document gets the SENT state and stays in the outbox. POST /api/documents/ ignores a direction value of INBOUND and always makes an outbound draft. Simulate inbound is the only method to fill the inbox of a sandbox company.
Testing received documents gives the full description. Resellers can do the same step through the Admin API: see Simulate an inbound document.

Frequently asked questions

No. The API has no such endpoint and no such field. Keep the processing status in your own system, with the document id as the key. See Prevent double processing.
It is not mandatory, but it is good practice. A poll at a long interval (for example one time each hour) finds the documents for which your endpoint missed the webhook. Because you record the processed document IDs, the poll does not process a document twice.
signed_url (UBL) and file_url (attachments) are valid for 1 hour. Each call to the endpoint returns a new URL.
For a production company: make sure that the company is registered as a receiver on Peppol with Look up Peppol participants. For a sandbox company: the inbox stays empty until you use Simulate inbound.
A received document gets one of four types: INVOICE, CREDIT_NOTE, SELFBILLING_INVOICE or SELFBILLING_CREDIT_NOTE. The type comes from the UBL document (Invoice or CreditNote) and its self-billing marker. Use the type parameter of GET /api/inbox/ to get one type.

Next Steps

Webhooks

Get an event for each received document and verify its signature.

List, filter and manage documents

Use the filters, the sort options and the pagination of the inbox.

Test mode and sandbox companies

Use a sandbox company and Simulate inbound to test your integration.

Document lifecycle and delivery tracking

Read the timeline of a received document.