Clark
The clerk: writes the invoice, keeps the record, sends it out.
Belgian B2B invoicing over the Peppol network, checked against the official rules before anything leaves the building.
A running demo of the real thing, open to anyone. It carries its own data, so anything you do in there stays well away from a real customer.
- Belgian B2B mandate
- 2026 Belgian B2B mandate
- validated against
- EN 16931 validated against
- for other applications
- API for other applications
- Role
- Product, architecture, build
- Period
- 2026 — now
- Stack
- Laravel Livewire Schematron bcmath Docker
The problem
Structured e-invoicing is now the way Belgian businesses invoice each other, and a rejected document is one the customer never received. The usual way an invoicing tool goes wrong is quiet: what you see on screen and what actually gets sent drift apart, and nobody finds out until the receiving side refuses the file. That failure is designed out here rather than tested for.
How it works
What you see on screen comes from the same calculation as what is sent — to the cent, using arithmetic that cannot introduce a rounding difference. The check against the official rules runs while you type, in plain language, with the rule code underneath for anyone who wants it: a missing buyer reference is trivial now and detective work after a rejection. The Peppol part is a separate component that knows nothing about the rest; Clark is the screen and the archive.
What is in it
Checked while you type
The quick checks run on every keystroke and read as sentences. The full official check is heavy and slow, so it runs once, just before transmission — using exactly the same rules the recipient will apply.
Validate, freeze, transmit — in that order
The invoice and the PDF are written to the archive before anything is sent. From the moment it goes out the document belongs to the recipient too; laying it out again later from a since-edited template would quietly produce a different document from the one they hold. A test asserts the archive is identical, letter for letter, to what was transmitted.
Nothing retries by itself
A refusal leaves the invoice editable with the reason attached — the state a person can act on. Reopening it shows why it came back. A failure in the layout never stops a valid invoice: the file that was sent is the legal original, and the PDF is a rendering of it.
Other applications invoice through it
Another application passes on what was sold. Layout, numbering, VAT presentation and the Peppol rules stay in Clark, so that application does not have to be changed every time an invoice design or a rule does.
Honest defaults
With no transmission contract in place, everything runs except the last step: checked, frozen, recorded, and nothing leaves. An installation that is not fully set up falls back to that rather than breaking — half-configured is the normal state of something still being built, and the screen that tells you what is missing has to stay reachable.
Words chosen carefully
"Past due date", never "unpaid" — nothing here tracks payment, and the wrong word sends somebody chasing a customer who settled last week. Received shows as unavailable rather than zero, because a zero would read as "none arrived".
The trade-off
What gets posted to the transmission provider is Clark's own invoice in the official form — not something in their house format. For a service priced per document that is the whole game: hand that form over and switching provider becomes a rewrite. It costs one translation step and buys the ability to leave.
Something like this on your list?
The projects differ, the way of working does not. Tell me what you are trying to solve.
Taking on new work