Skip to main content

Overview

The Document schema defines the structure of invoices, credit notes and debit notes in the e-invoice.be API. You send this schema when you call POST /api/documents/ or POST /api/validate/json.
Only the items array is required, with a minimum of one line. All other fields are optional, but a document needs most of them to pass the Peppol BIS Billing 3.0 rules.
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.

Document metadata

enum
default:"INVOICE"
Type of document to create.
  • INVOICE - Standard invoice
  • CREDIT_NOTE - Credit note (refund or correction)
  • DEBIT_NOTE - Debit note
  • SELFBILLING_INVOICE - Self-billed invoice
  • SELFBILLING_CREDIT_NOTE - Self-billed credit note
See Self-billing and debit notes for the two self-billing types and for debit notes.
enum
default:"DRAFT"
Document state. See Document states.
enum
default:"OUTBOUND"
Document direction.
  • OUTBOUND - Document that you send to a customer
  • INBOUND - Document that you receive from a supplier

Document states

You can send a document only when it is in the DRAFT or FAILED state. For the transitions, the retry behaviour and the webhook events of each state, see Document lifecycle and delivery tracking. See Document lifecycle and delivery tracking for the state diagrams, the transitions, the retries and the related webhook events.

Vendor (supplier) information

string
Legal name of the vendor.Example: "E-INVOICE BV"
string
VAT number of the vendor, with the country prefix. The API changes the value to uppercase and removes all characters other than A-Z and 0-9. See Normalisation and rounding.Example: "BE1018265814"The API derives the Peppol participant ID of the sender from this value when it sends the document. See Look up Peppol participants for Peppol routing.
string
Address of the vendor as one string. See Addresses for the format that the API can split correctly.Example: "Brusselsesteenweg 119/A, 1980 Zemst, BE"
string
Department or person at the vendor address. The API writes this value as the contact name only when vendor_email is present.Example: "Accounts Department"
string
Contact email address of the vendor.Example: "billing@e-invoice.be"

Customer (buyer) information

string
Legal name of the customer.Example: "OpenPeppol VZW"
string
VAT number of the customer, with the country prefix. The API changes the value to uppercase and removes all characters other than A-Z and 0-9.Example: "BE0848934496"
string
Peppol participant ID of the customer, in the format scheme:identifier. When you send this field, the API uses it as the receiver of the document and does not derive the receiver from customer_tax_id.Example: "0208:0848934496"The API does not store this field with the document. The value is kept only as the receiver of the generated UBL. See Look up Peppol participants to find and check a Peppol ID before you send.
string
Your internal reference for the customer. The API writes it as the party identification of the customer. It is also the fallback value of BuyerReference when purchase_order is absent.Example: "CUST-12345"
string
Address of the customer as one string. See Addresses.Example: "Rond-point Schuman 6, 1040 Brussels, BE"
string
Department or person at the customer address. The API writes this value as the contact name only when customer_email is present.Example: "Accounts Payable"
string
Contact email address of the customer.Example: "ap@openpeppol.example"

Invoice details

string
Unique invoice number.Example: "INV-2026-001"
string
Issue date in ISO 8601 format (YYYY-MM-DD).Example: "2026-10-01"
string
Payment due date in ISO 8601 format (YYYY-MM-DD). The API does not write this field to the UBL of a credit note.Example: "2026-10-31"
string
Purchase order reference of the customer. For credit notes, use this to reference the original invoice.Example: "PO-12345" or "INV-2026-001" (for credit notes)
string
Free-text note.Example: "Full refund - goods returned"
string
Description of the payment terms.Example: "Payment due within 30 days"

Financial fields

The API calculates subtotal, total_discount, total_tax, invoice_total and amount_due when they are absent. When you send them, the API compares them with its own calculation. See Invoice totals and calculations for the formulas.
enum
default:"EUR"
Currency code (ISO 4217).The currency field accepts these ISO 4217 codes:EUR, USD, GBP, JPY, CHF, CAD, AUD, NZD, CNY, INR, SEK, NOK, DKK, SGD, HKDThe default is EUR.Example: "EUR"
number
Taxable base amount (after document-level allowances and charges, before tax).Corresponds to UBL cac:LegalMonetaryTotal/cbc:TaxExclusiveAmountExample: 1000.00
number
Total of the document-level allowances (discounts only, not charges).Corresponds to UBL cac:LegalMonetaryTotal/cbc:AllowanceTotalAmountExample: 50.00
number
Total VAT amount.Corresponds to UBL cac:TaxTotal/cbc:TaxAmountExample: 210.00
number
Total amount with tax (subtotal + total_tax).Corresponds to UBL cac:LegalMonetaryTotal/cbc:TaxInclusiveAmountExample: 1210.00
number
Amount due for payment after prepayments.Corresponds to UBL cac:LegalMonetaryTotal/cbc:PayableAmountExample: 1210.00
number
Previous outstanding balance. This is an internal field: the API does not write it to the generated UBL.Example: 100.00

Tax information

enum
default:"S"
Tax category code (UNCL5305).
  • S - Standard rate (most common)
  • Z - Zero rated
  • E - Exempt from tax
  • AE - VAT reverse charge
  • K, G, O, L, M, B - Other special cases
When tax_code is K (intra-community supply), each line item must have a tax_rate of 0.00.
enum
VAT exemption reason code (when tax_code is E, AE, K, G, O, L, M or B).Example: "VATEX-EU-IC" for an intra-community supply
string
Text that explains the VAT exemption.Example: "Reverse charge applies - Art. 196 EU VAT Directive"

Service period

string
Start date of the service period (ISO 8601: YYYY-MM-DD).Example: "2026-09-01"
string
End date of the service period (ISO 8601: YYYY-MM-DD).Example: "2026-09-30"

Additional addresses

Of these fields, the API writes only shipping_address and shipping_address_recipient to the generated UBL (as cac:Delivery). The billing, service and remittance fields are kept with the document, but the receiver does not get them in the UBL.
string
Billing address (if different from the customer address).Example: "Rond-point Schuman 6, 1040 Brussels, BE"
string
Recipient at the billing address.Example: "Accounts Payable Department"
string
Delivery address. The API writes it to cac:Delivery/cac:DeliveryLocation/cac:Address with the same split rule as the party addresses.Example: "Industrieweg 5, 3000 Leuven, BE"
string
Recipient at the delivery address. The API writes it as the name of the delivery party.Example: "Warehouse Manager"
string
Address of the service location.Example: "Industrieweg 5, 3000 Leuven, BE"
string
Recipient at the service address.
string
Remittance (payment) address.Example: "Brusselsesteenweg 119/A, 1980 Zemst, BE"
string
Recipient at the remittance address.

Line items

array
required
Array of line items (minimum 1).See the LineItem schema for the fields.Example:

Payment details

array
Array of payment instructions. The API writes one cac:PaymentMeans element for each entry, always with payment means code 30 (credit transfer).Example:

Allowances and charges

array
Document-level allowances (discounts).Example of a 10% allowance:
array
Document-level charges (fees).Example:
See Advanced invoicing for the effect of allowances and charges on the totals.

Tax details

array
Tax breakdown for each category and rate.The API calculates the breakdown when it is absent.

Attachments

array
Files in this array are embedded in the UBL. See Attachments and PDF for the permitted file types and for the construct_pdf option.Example:

How fields map to UBL

The API converts the JSON document to UBL BIS Billing 3.0. The table shows the conversions that are not self-evident. The response of POST /api/validate/json contains the generated UBL, thus you can examine the result for your own payload. The MIME type of an attachment in the UBL is file_type when it is one of application/pdf, image/png, image/jpeg, text/csv, application/vnd.openxmlformats-officedocument.spreadsheetml.sheet (xlsx) or application/vnd.oasis.opendocument.spreadsheet (ods). For a different file_type, the API uses the extension of file_name (.pdf, .png, .jpg, .jpeg, .csv, .xlsx, .ods) to find the MIME type.

Addresses

vendor_address, customer_address and shipping_address are single strings. The API splits each string into the parts of a UBL address with these rules:
  1. The API splits the string on new lines. If there is only one line, it splits the string on a comma followed by a space (", ").
  2. Part 1 is the street (cbc:StreetName).
  3. Part 2 is the postal code and the city. When the part has the form “postal code, space, city”, the API writes cbc:PostalZone and cbc:CityName. If not, the full part is the city.
  4. The last part is the country (cac:Country/cbc:IdentificationCode) only if it has 2 or 3 letters and no other characters. The API changes it to uppercase.
  5. For the vendor and the customer, if the last part is not a country code, the API uses the first two characters of the tax ID of that party. If there is no tax ID, the country is BE. For shipping_address, the API does not use the tax ID: the country is BE when the string has no country code.
Use this format, with the ISO 3166-1 alpha-2 country code as the last part:
The first address gives this UBL:
The API does not read a country name as a country. With "..., 1000 Brussels, Belgium", the API ignores Belgium and takes the country from the tax ID prefix, or uses BE. An address in a different country, with a country name and without a tax ID, gets the country BE. Always end the address with the two-letter country code.
Do not put a comma followed by a space in the street part (for example "Main Street 1, box 5"). The API reads the text after the comma as the postal code and city. A last part that has only 2 or 3 letters is always read as a country code.
When the address is absent or has no usable parts, the API writes Unknown Street and Unknown City.

Normalisation and rounding

The API changes some values before it stores the document and generates the UBL. Rounding of monetary amounts is half-up to 2 decimals (0.005 becomes 0.01). The API rounds in this sequence:
  1. Each line amount is rounded.
  2. For each tax group, the API adds the rounded line amounts, subtracts the document-level allowances and adds the document-level charges. A tax group is one combination of tax category and tax rate.
  3. The tax of each group is taxable amount × rate / 100, rounded.
  4. total_tax is the sum of the group taxes.
The API thus calculates VAT for each tax group, not for each line. If you calculate VAT for each line and add the results, your total_tax can be different by some cents. See Invoice totals and calculations.

Example

Complete invoice:
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.

Next Steps

LineItem

Look up the fields of an invoice line.

Create e-invoices

Create and send an invoice with this schema.

Invoice totals and calculations

Calculate the totals that the API checks.

Validation during development

Validate a payload and examine the generated UBL.