Overview
The API has two validation endpoints:POST /api/validate/jsonconverts your JSON to UBL and examines the result against the rules of EN 16931 and Peppol BIS Billing 3.0.POST /api/validate/ublexamines a UBL XML file that you made yourself.
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.Why validate
- No document is created: you can repeat the call as often as necessary.
- All rule failures in one response: each issue has a rule ID and a message.
- The generated UBL: a valid result contains the XML that the API makes from your JSON.
- Fewer rejected create requests: you correct the payload before you call
POST /api/documents/.
Validate a JSON document
Send the document JSON toPOST /api/validate/json. The body is the same as the body of POST /api/documents/.
POST /api/validate/json does not compare the vendor with your company. POST /api/documents/ does: before you create the document, replace the vendor fields with those of your own company.
When the document is valid, the API returns 201 Created with the result and the generated UBL:
201 Created
ubl_document value is shortened in this example.
string
required
The identifier of this validation. It is not a document ID.
string
required
The name of the generated XML file (
<id>.xml). For POST /api/validate/ubl, the name of the file that you uploaded.boolean
required
false when one issue or more has the flag fatal or is a failure of the XML schema (rule_id is xsd-validation).array
required
The rule failures and warnings. Each issue has
message, type (error or warning) and schematron (the rule set that found the issue). An issue can also have rule_id, flag, location and test. For the description of each field, see Validation result.string
The generated UBL XML.
POST /api/validate/json returns this field only when is_valid is true. POST /api/documents/{document_id}/validate always returns it.A document that breaks rules
A rule failure does not change the HTTP status code. The API returns201 Created, is_valid is false, and issues contains the failures. Thus your code must read is_valid, not only the status code.
This payload has two faults: the vendor enterprise number is not a real number, and the line has no amount. It is a failing example on purpose.
Request body with faults
201 Created
ubl_document, because the document is not valid. To correct the payload:
- Use an enterprise number that passes the modulo 97 check:
BE1018265814in place ofBE0123456789. This removesPEPPOL-COMMON-R043. - Add
amountto the line:"1000.00"(quantity×unit_price). This removesBR-S-08andPEPPOL-EN16931-R120.
Totals that are not consistent
Before the API generates the UBL, it calculates the totals from the lines and compares them withsubtotal, total_tax, total_discount, invoice_total and amount_due in your JSON. If a value is different from the calculated value by more than 1.00, or if amount_due is more than the calculated invoice total, the API stops. It returns 406 Not Acceptable with one text message, and no issues list:
406 Not Acceptable
Total tax mismatch, Total discount mismatch, Invoice total mismatch or Amount due (...) cannot be greater than invoice total (...). When more than one total is wrong, the list in the message has one entry for each total. POST /api/documents/ returns the same 406 for the same payload.
A request that does not agree with the schema (for example a date that is not YYYY-MM-DD, or a currency code that is not supported) returns 422 before the rules run. See Request validation error (422).
Validate a UBL XML file
UsePOST /api/validate/ubl to examine a UBL BIS Billing 3.0 XML file that you have.
201 Created with the validation result. A valid file gives:
201 Created
is_valid set to false:
201 Created
schematron field names the Schematron rule set that found the issue: CEN-EN16931-UBL, PEPPOL-EN16931-UBL, PEPPOL-EN16931-UBL-SB (self-billing) or XSD (the XML schema).
Common mistake: raw XML body
If you setContent-Type: application/xml and send the XML as the raw request body (for example with --data-binary @invoice.xml), the API returns this 422 response:
422 Unprocessable Entity
multipart/form-data with a file form field, as the examples above show.
When to use UBL validation
UsePOST /api/validate/ubl when you:
- have UBL XML files from your ERP system and want to examine them before you send them
- move from a different Peppol Access Point and have UBL documents that are already generated
- get UBL files from an external source and want to examine them before you post them to
POST /api/documents/ubl
Common validation problems
The
currency field accepts these ISO 4217 codes:
EUR, USD, GBP, JPY, CHF, CAD, AUD, NZD, CNY, INR, SEK, NOK, DKK, SGD, HKD
The default is EUR.
The tax_rate of a line is a percentage with two decimals as a string, for example "21.00", "6.00" or "0.00".
For the rule ID reference, all HTTP status codes and the error body formats, see Errors and troubleshooting.
Development workflow
1
Build the invoice JSON
Start from the example in Validate a JSON document and replace the values with your data. For the fields, see Create e-invoices and the document schema.
2
Validate the JSON
Send the JSON to
POST /api/validate/json. If the status code is 406 or 422, or if is_valid is false, correct the JSON and send it again.3
Create the document
When
is_valid is true, send the same JSON to POST /api/documents/. The API creates the document in the state DRAFT.Complete example
These programs validate a document and create it only when the result is valid. Put your document JSON in the fileinvoice.json. The vendor in the file must be your own company.
Node.js
Node.js
validate-and-create.mjs
Python
Python
validate_and_create.py
Testing strategy
During development
UsePOST /api/validate/json for each change of your payload:
- Edge cases: validate unusual documents (zero amounts, more than one VAT rate, a currency other than EUR).
- All document types: validate invoices, credit notes and debit notes.
- Short cycles: correct the JSON and validate again. No document is created.
- Automated tests: add validation calls to your test suite.
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.
Before production
- Validate representative samples of all the invoice types that you send.
- Make sure that each receiver is registered on Peppol. See Look up Peppol participants.
- Validate all the tax categories and currency codes that you use.
- Validate complex documents (allowances, charges, many lines). See Advanced invoicing.
Best practices
Validate early and frequently
Validate early and frequently
Do not wait until production:
- Validate each new invoice template.
- Validate again after a change in your mapping or in the schema.
- Add validation to your CI/CD pipeline.
Handle validation results in your code
Handle validation results in your code
Three results are possible. Handle each of them:
201andis_validistrue: continue withPOST /api/documents/.201andis_validisfalse: record therule_idand themessageof each issue, and do not create the document.406or422: record thedetailvalue, and do not create the document.
Validate templates one time
Validate templates one time
If you generate invoices from a template, validate one document of each template when the template changes. The create request applies the rules again to each document, so a validation call for each invoice in production is not necessary.
Next Steps
Create e-invoices
Create and send validated invoices
Errors and troubleshooting
Find the cause of a status code or a rule ID
Invoice totals and calculations
Calculate totals that pass the checks
Look up Peppol participants
Find the Peppol ID of a receiver