Frequently asked questions
What is darvis/ubl-peppol?
A PHP library that builds UBL 2.1 e-invoices for PEPPOL BIS Billing 3.0, the format the PEPPOL network requires. UblNlBis3Service builds Dutch invoices and UblBeBis3Service builds Belgian invoices and credit notes. An optional Laravel layer posts the XML to your access point provider. It is free and MIT licensed.
How do I create a PEPPOL invoice in PHP or Laravel?
Run composer require darvis/ubl-peppol, create a UblNlBis3Service or UblBeBis3Service, call createDocument(), add the header, the parties, the payment means, the tax total, the monetary total and the lines, then call generateXml(). The page “Your first invoice” has a complete example you can copy.
Which PHP and Laravel versions does it need?
PHP 8.2 or newer with the dom and libxml extensions. The bcmath extension is needed to check an IBAN and the soap extension for the VIES check. Laravel 11, 12 or 13 is only needed for the optional Laravel layer; the builders and the validators are plain PHP.
Does this package send my invoices to the PEPPOL network?
Not by itself. It is not an access point. In Laravel, PeppolService posts the XML to the API of an access point provider you have a contract with, using HTTP Basic authentication and the values PEPPOL_URL, PEPPOL_USERNAME and PEPPOL_PASSWORD. A provider whose API works differently needs your own sending code.
What is the difference between the Dutch and the Belgian builder?
Pick the builder by the country of the receiver. UblNlBis3Service builds invoices only, sorts the elements into schema order itself, and its validate() checks code formats and five Dutch NL-R rules. UblBeBis3Service needs its methods called in schema order, and its validate() checks that the amounts add up. Both build credit notes.
Can I create a credit note?
Yes, with both builders; the Dutch builder has credit notes since 1.10.0. Start with createCreditNoteDocument(), add addBillingReference() for the invoice you correct, and add lines with addCreditNoteLine(). All amounts are positive. generateXml() throws when the billing reference is missing (BR-55); the Belgian builder also throws when a total is negative.
Does validate() fix my invoice, and is a valid result enough?
No to both. validate() changes nothing. getCorrections() returns suggested totals, only from the Belgian builder and only when the amounts do not add up. The package checks the rules it implements, which is less than the Schematron a receiver runs, so check a document with an official PEPPOL validator before you go live.
Does a valid VIES answer prove the VAT number is correct?
It proves the number is registered at the moment you ask, not that it belongs to your customer. When VIES cannot answer, ViesService also returns valid false, but with a message in error. Treat that as unknown, never as invalid.
Is the peppol_logs table required?
No. Publish it with php artisan vendor:publish --tag=ubl-peppol-migrations and run php artisan migrate only if you want a record of each attempt to send. Without the table PeppolService sends the same way and the result has a log_id of null.
How do I test code that sends invoices without calling my provider?
PeppolService uses Laravel’s HTTP client, so Http::fake() replaces the provider and Http::preventStrayRequests() stops any real request. ViesService uses SOAP; replace it in the container with $this->mock(ViesService::class, ...). The Testing page has complete examples.