Overview
TheDocument 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.
The schema requires only the
items array, with a minimum of one line. All other fields are optional in the schema. But POST /api/documents/ accepts a document only if it also has:- A vendor identifier (
vendor_tax_idorvendor_company_id) and a customer identifier (customer_peppol_id,customer_tax_idorcustomer_company_id). The derived Peppol ID of the sender must be one of thepeppol_idsof your company (406if not). invoice_id(ruleBR-02) andvendor_name.- A
description(orname), aquantityand aunit_pricefor each line. A line withoutquantityorunit_pricecounts as 0.00 in the totals. - For an invoice with a positive amount due:
due_dateorpayment_term(ruleBR-CO-25).
invoice_date is the current date, unit is NAR, a missing address becomes Unknown Street and Unknown City, and a line with tax_rate 0.00 gets tax category Z when tax_code is S.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 invoiceCREDIT_NOTE- Credit note (refund or correction)DEBIT_NOTE- Debit noteSELFBILLING_INVOICE- Self-billed invoiceSELFBILLING_CREDIT_NOTE- Self-billed credit note
enum
default:"DRAFT"
Document state. See Document states. Read-only:
POST /api/documents/ always sets DRAFT and ignores the value that you send.enum
default:"OUTBOUND"
Document direction. Read-only:
POST /api/documents/ always sets OUTBOUND and ignores the value that you send.OUTBOUND- Document that you send to a customerINBOUND- 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 ID of the vendor from this value. For the document types other than self-billing, the vendor is the Peppol sender. See Peppol ID routing.string
Company registration number of the vendor, for example the Belgian enterprise number (CBE) or the Dutch KVK number. The API uses it to derive the Peppol ID of the vendor when
vendor_tax_id is absent.Example: "1018265814"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
Company registration number of the customer. The API uses it to derive the Peppol ID of the customer when
customer_peppol_id and customer_tax_id are absent.Example: "0848934496"string
Peppol participant ID of the customer, in the format
scheme:identifier. When you send this field, the API uses it as the Peppol ID of the customer and does not derive it from customer_tax_id or customer_company_id. The customer is the Peppol receiver, except in a self-billing document, where the customer is the Peppol sender.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 buyer_reference and purchase_order are absent. The API does not use it to find the Peppol ID of the customer.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). When it is absent, the API uses the current date.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
Buyer reference (BT-10), for example a cost centre or a reference that the buyer asks for. The API writes it to
cbc:BuyerReference.Example: "CC-4410"string
Purchase order reference of the customer (BT-13). The API writes it to
cac:OrderReference/cbc:ID, and to cbc:BuyerReference when buyer_reference is absent. Do not use it for the number of the original invoice of a credit note: use preceding_invoice_id.Example: "PO-12345"string
Sales order reference of the vendor (BT-14). The API writes it to
cac:OrderReference/cbc:SalesOrderID. When purchase_order is absent, the API writes NA as the order reference ID.Example: "SO-2026-0042"string
Number of the invoice that this document corrects (BT-25), for example the invoice that a credit note credits. The API writes it to
cac:BillingReference/cac:InvoiceDocumentReference/cbc:ID.Example: "INV-2026-001"string
Issue date of the preceding invoice (BT-26) in ISO 8601 format (
YYYY-MM-DD). The API writes it only together with preceding_invoice_id.Example: "2026-10-01"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 calculatessubtotal, 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.00number
Total of the document-level allowances (discounts only, not charges).Corresponds to UBL
cac:LegalMonetaryTotal/cbc:AllowanceTotalAmountExample: 50.00number
Total VAT amount.Corresponds to UBL
cac:TaxTotal/cbc:TaxAmountExample: 210.00number
Total amount with tax (
subtotal + total_tax).Corresponds to UBL cac:LegalMonetaryTotal/cbc:TaxInclusiveAmountExample: 1210.00number
Amount due for payment after prepayments.Corresponds to UBL
cac:LegalMonetaryTotal/cbc:PayableAmountExample: 1210.00number
Previous outstanding balance. This is an internal field: the API does not write it to the generated UBL.Example:
100.00Tax information
enum
default:"S"
Tax category code (UNCL5305).
S- Standard rate (most common)Z- Zero ratedE- Exempt from taxAE- VAT reverse chargeK,G,O,L,M,B- Other special cases
tax_rate: a rate more than 0.00 gives S. A rate of 0.00 gives the tax_code of the document, or Z when tax_code is S.When tax_code is K (intra-community supply), each line item must have a tax_rate of 0.00 (422 if not).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, "VATEX-EU-AE" for a reverse chargeWhen vatex is VATEX-EU-O (not subject to VAT), vendor_tax_id and customer_tax_id must be empty (406 if not).string
Text that explains the VAT exemption. When you send
vatex_note, the UBL contains only this text as the exemption reason, and not the vatex code.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. When tax_code is K and there is no shipping address, the API writes only the country of the customer as the delivery location.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
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:
Tax details
array
Tax breakdown for each rate. Optional. The API stores and returns the entries as you send them. It does not calculate them, and it does not use them for the tax breakdown in the UBL (the API always calculates that breakdown).Each entry has
amount (number, the tax amount) and rate (string, for example "21.00").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 ofPOST /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:
- 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 (
", "). - Part 1 is the street (
cbc:StreetName). - Part 2 is the postal code and the city. When the part has the form “postal code, space, city”, the API writes
cbc:PostalZoneandcbc:CityName. If not, the full part is the city. - 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. - 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. Forshipping_address, the API does not use the tax ID: the country isBEwhen the string has no country code.
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:
- Each line
amountis rounded. - 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.
- The tax of each group is
taxable amount × rate / 100, rounded. total_taxis the sum of the group taxes.
total_tax can be different by some cents. See Invoice totals and calculations.
Example
Complete invoice:Invoice
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.