DEV Community

Cover image for Add Peppol e-invoicing to your SaaS — the easy way to get ahead of the EU mandates
Zero Lopp Labs
Zero Lopp Labs

Posted on • Originally published at dev.to

Add Peppol e-invoicing to your SaaS — the easy way to get ahead of the EU mandates

When you're building a young B2B SaaS, Peppol e-invoicing lives in the "we'll deal with it later" pile. Invoicing is a feature, not your product. No customer has demanded it yet. And the whole thing looks like XML plumbing for an EU regulation that may not even apply to you this year.

Here's the trap: "later" has a habit of arriving as "this sprint, and it's now on fire." A customer signs, and during onboarding asks whether you can send their invoices over Peppol. Or your home market publishes a mandate date and your roadmap gets rewritten for you.

This article makes the opposite case. For an early-stage SaaS, the cheapest and lowest-risk time to add Peppol is before you're forced to — not because of urgency theatre, but because of how the costs actually break down once you look at them.

Where the EU mandates stand today

You don't need to memorise EU tax law. You need to know that the deadlines are real, dated, and arriving on a schedule you can plan around:

Market Receive Send (issue) Network
🇧🇪 Belgium Mandatory since 1 Jan 2026 (in-scope domestic Belgian VAT-liable B2B) Mandatory since 1 Jan 2026 (in-scope domestic Belgian VAT-liable B2B) Structured e-invoice, generally via Peppol
🇫🇷 France 1 Sept 2026 (all businesses) 1 Sept 2026 (large + mid-sized); 1 Sept 2027 (SMEs & micro) Approved platforms; EN 16931 formats such as Factur-X, UBL and CII
🇩🇪 Germany Since 1 Jan 2025 (domestic B2B must be able to receive) Transition rules through 2026; through 2027 for issuers up to €800K prior-year turnover EN 16931, typically XRechnung or ZUGFeRD; Peppol optional
🇪🇺 EU (ViDA) 1 July 2030 (intra-EU cross-border B2B digital reporting) Real-time reporting based on e-invoicing / EN 16931

Primary references: Belgium's e-facture FAQ, France's impots.gouv.fr calendar, Germany's BMF e-invoice FAQ, and the European Commission's ViDA page.

Poland, Romania and Spain are phasing in their own mandates on top of these. The pattern is one-directional: structured e-invoicing is becoming the default for B2B across the bloc, with Peppol either mandated, supported or sitting close to the infrastructure in several markets. The EU's VAT in the Digital Age (ViDA) package locks in the cross-border digital-reporting layer for 2030.

The takeaway for a young SaaS is the good kind: you still get to choose when you do this work, on your own terms. Even if you aren't directly in scope yet, a growing share of your EU B2B customers either already are, or will be soon — and the direction of travel won't reverse. Doing it early and calmly is worth real money.

The two costs nobody puts on the roadmap

When founders estimate "add Peppol," they price the obvious thing — a vendor's monthly fee — and skip the two costs that actually hurt.

The build cost. Peppol looks like "just an XML format." It isn't. To send a compliant invoice you have to emit UBL 2.1 conforming to Peppol BIS Billing 3.0, with country-specific extensions (CIUS) layered on top. Then you need to:

  • Map your invoice model to UBL (your data shape is not UBL's shape)
  • Pass schema and Schematron validation before sending, or the access point rejects you
  • Look up recipients in the Peppol Directory across participant identifier schemes (0208 for Belgium, 0009 for France, 0007 for Sweden, 0088 for GLN, and so on)
  • Submit through a certified Access Point — you don't talk to recipients directly, and becoming an Access Point yourself is a multi-month, audited, fee-bearing project almost no SaaS takes on
  • Handle asynchronous delivery, where "accepted by the access point" is not "delivered," which is not "accepted by the recipient's accounting system"
  • Surface failures that can arrive hours later when a recipient rejects for a compliance reason
  • Archive everything in machine-readable form for seven years

In our experience that's roughly one backend engineer for two quarters to ship a first version — then ongoing maintenance every time a country updates its CIUS or a new mandate lands. For a team where invoicing is a feature and not the product, that's a tax you pay forever.

The cost of waiting. Do this work under a mandate deadline and you pay a rush premium. There's no time to learn the failure modes in a calm sandbox, no buffer for the recipient-rejected-it-on-Tuesday surprises, and no room to ship behind a flag and watch it for a week. In markets where the mandate is already live, there's also direct fine exposure — Belgium's regime runs €1,500 to €5,000 per escalating offence (the Belgium developer playbook covers exactly how that lands on engineering).

Against either of those, the line item everyone fixates on — what the API costs per month — is the cheapest part of the whole story.

Why "start early" is structurally cheaper

It's not a motivational slogan; it's a difference in how the work behaves.

When you have time, you integrate at your own pace. You wire the SDK into a sandbox that's free and unlimited, push fake invoices through, and deliberately break things to learn what invoice.refused looks like before it matters. You ship behind a feature flag, run it read-only alongside your existing flow, and make Peppol boring — which is exactly what infrastructure should be.

When you're under a deadline, you do the same work serially, at speed, with a fine clock ticking and a customer waiting. Same code, very different stress — and a meaningfully higher chance of shipping something that passes your tests but trips a recipient's Schematron in production.

There's an upside most founders miss, too: being Peppol-ready early is a sales asset. When an EU B2B prospect asks "can you send our invoices over Peppol?", "yes, today" closes deals that make your competitors say "it's on the roadmap."

The early-stage on-ramp: sandbox, then a pilot

This is where getpeppr fits, and it's built around exactly this "start small" shape. (It's what we ship — but the reasoning holds for any decent Peppol-as-a-service API.) The whole idea is a TypeScript-first wrapper around a certified Access Point: a JSON object goes in, a Peppol-compliant invoice goes out, and you never touch the XML unless you ask to.

Step one is free. Create an account and the sandbox is yours — free forever, no credit card, no time limit. You get the full SDK surface, real validation errors, and webhook events — just no live Peppol traffic. This is where a young team should live for the first week: learn the model with zero commitment.

Step two is a pilot, not a platform contract. When you're ready to send for your first real customers, the Platform Pilot tier is sized for precisely that moment: €99/month, up to 10 production Legal Entities, €0.35 per successfully sent document, as a 6-month pilot bridge. It's described as being "for early SaaS platforms validating production Peppol with first customers," includes guided onboarding, and has a defined conversion path to the larger Starter and Growth tiers as you grow.

Be aware of one honest caveat: production sending is contract-gated — a signed platform agreement and a DPA are required before live customer sending is enabled. That isn't a paywall; it's the compliance reality of sending invoices on another company's behalf. Plan a few days for it rather than discovering it the afternoon a customer wants to go live.

If you're sending your own invoices rather than acting as a platform, the direct-business tiers are public and self-serve: Starter €49/mo (100 docs), Pro €149/mo (800 docs), Business €399/mo (2,000 docs), with overage from €0.20/doc.

The TypeScript path, in about fifteen lines

Here's the entire happy path. The code uses real @getpeppr/sdk v1.5.0 calls.

Install and initialise. Keys are environment-prefixed — sk_sandbox_... for test, sk_live_... for production. Switching environments is a key change, not a code change.

npm install @getpeppr/sdk
Enter fullscreen mode Exit fullscreen mode
import { Peppol } from "@getpeppr/sdk";

const peppol = new Peppol({ apiKey: process.env.GETPEPPR_API_KEY });
Enter fullscreen mode Exit fullscreen mode

Send an invoice. The shape mirrors the EN 16931 model — supplier, customer, line items with VAT — but stays JSON-shaped:

const result = await peppol.invoices.send({
  number: "INV-2026-001",
  from: {
    name: "Your Customer Ltd",
    peppolId: "0208:BE0456789012", // the legal entity sending
    country: "BE",
  },
  to: {
    name: "Acme Corp",
    peppolId: "0208:BE9876543210",
    street: "123 Business Ave",
    city: "Brussels",
    postalCode: "1000",
    country: "BE",
  },
  lines: [
    { description: "Consulting services", quantity: 10, unitPrice: 150, vatRate: 21 },
  ],
});
Enter fullscreen mode Exit fullscreen mode

Under the hood the SDK builds UBL 2.1, validates it against Peppol BIS Billing 3.0, signs the envelope, and submits via the Access Point.

Validate offline first, with no key at all. The @getpeppr/cli package (v0.4.3) generates, validates and converts invoices entirely offline. Use it to sanity-check your JSON shape before you wire up the live API:

npx @getpeppr/cli validate my-invoice.json
Enter fullscreen mode Exit fullscreen mode

Handle status asynchronously. Peppol delivery isn't synchronous — send() gives you a queued ID, and the rest arrives via webhooks (invoice.sent, invoice.accepted, invoice.refused, invoice.error, invoice.paid, and friends). Signatures are HMAC-SHA256 on the Getpeppr-Signature header, and the SDK verifies them for you:

const event = peppol.webhooks.constructEvent(
  req.body,
  req.headers["getpeppr-signature"] as string,
  process.env.PEPPR_WEBHOOK_SECRET!,
);

if (event.type === "invoice.refused") flagForReview(event.data.invoiceId);
Enter fullscreen mode Exit fullscreen mode

That's the whole surface. If you're sending on behalf of many customers — the multi-tenant case where one master API key fans out to N legal entities — the platform integration docs cover that model end to end (master keys, per-tenant legal entities, KYB), and the multi-tenant pattern (G2 in this series) walks through the code.

The boring truth about doing it later

Retrofitting Peppol under a deadline is the same engineering as doing it calmly now — minus the safety margins. You lose the sandbox-learning week, the flag-gated rollout, the parallel-run validation, and the option to push a fix without a customer breathing down your neck. You also lose negotiating leverage: "we need this live in three weeks" is not the position you want to be in with any dependency.

Starting early converts a future fire drill into a quiet afternoon of integration work. For a young SaaS, that trade is almost always worth making while it's cheap.

Next steps

  • Create a sandbox key — free, no credit card, full SDK. Push a fake invoice through this week.
  • Validate one of your real invoices offline first: npx @getpeppr/cli validate your-invoice.json. Two minutes, zero commitment.
  • For the regulatory context, read the Belgium developer playbook (G1). For the multi-tenant architecture, read how to add Peppol to your SaaS (G2).
  • Building a platform that sends for many customers? The platform integration docs cover master API keys, per-tenant legal entities, and KYB by country.

No call required, no demo to book — just an API key. The mandates are arriving on a published schedule, and the calmest time to get ready is now, on your own terms.

— Zero Loop Labs

Top comments (0)