# E-Invoice Validator: XRechnung, ZUGFeRD, Factur-X, Peppol (`lerider/einvoice-validator`) Actor

Validate e-invoices against the official EN 16931, Peppol BIS 3.0 and XRechnung 3.0 rules: UBL, CII and Factur-X/ZUGFeRD PDFs. ALLOW / REVIEW / BLOCK verdict, every error with its rule ID, plus the invoice summary. For AP automation and AI agents.

- **URL**: https://apify.com/lerider/einvoice-validator.md
- **Developed by:** [Lerider Technologies](https://apify.com/lerider) (community)
- **Categories:** Developer tools, Agents
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$4.00 / 1,000 e-invoice validateds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## E-Invoice Validator: XRechnung, ZUGFeRD, Factur-X, Peppol

> **Open source (Apache-2.0):** [read the code on GitHub](https://github.com/LeriderTechnologies/eu-compliance-actors/tree/main/einvoice-validator): see exactly what this Actor does with your data, run the tests, or host it yourself.

**Is this e-invoice valid, and will the receiver accept it?** This Actor checks e-invoices against the **official
validation rules**: the European standard **EN 16931** (CEN/TC 434 rules, as published by the European Commission),
**Peppol BIS Billing 3.0** and **XRechnung 3.0**, plus the UBL 2.1 and UN/CEFACT CII XML schemas. It returns one
verdict per invoice, `ALLOW`, `REVIEW` or `BLOCK`, every error and warning with its official rule ID, and a summary
of the invoice (number, dates, seller, buyer, totals, IBAN).

Built for AI agents and automations in accounts payable and receivable: check an invoice before you send it to
Peppol or a German public portal, or before you book and pay one you received; and for e-invoicing projects that
need a quick, current validator in a pipeline.

### Formats

| Format | How it is recognised | Rules applied |
|---|---|---|
| **UBL 2.1** Invoice / CreditNote | root element | XML schema + EN 16931 |
| **UN/CEFACT CII** D16B | root element | XML schema + EN 16931 |
| **Peppol BIS Billing 3.0** | `CustomizationID` …`poacc:billing:3.0` | + Peppol rules |
| **XRechnung 3.0** (UBL or CII) | `CustomizationID` …`kosit:xrechnung_3.0` | + XRechnung rules (e.g. Leitweg-ID) |
| **Factur-X / ZUGFeRD 2.x** PDF | embedded `factur-x.xml` / `zugferd-invoice.xml` / `xrechnung.xml` | XML rules for its profile; PDF metadata cross-checked |

Use `profile` to apply rules the invoice doesn't declare, e.g. check a plain EN 16931 invoice against XRechnung
before sending it to a German public authority.

### Verdicts

| Verdict | When |
|---|---|
| `ALLOW` | No errors against any applicable rule set (warnings are listed; they don't make an invoice invalid) |
| `REVIEW` | No errors, but not a full e-invoice under the mandates: Factur-X/ZUGFeRD **MINIMUM** or **BASIC WL** (no line items, so not a complete EN 16931 invoice), or an **outdated XRechnung 1.x/2.x** identifier |
| `BLOCK` | Errors: wrong totals or VAT breakdown, missing mandatory fields, invalid codes, XML schema errors; or the file is not an e-invoice (plain PDF, other XML, ZUGFeRD 1.0, Order-X) |

`valid` is `true` only for `ALLOW`.

### Pricing

| Event | Price | When |
|---|---|---|
| `invoice-validation` | **$0.004** | An e-invoice was validated (any verdict: errors found are an answer) |
| (free) | $0 | Not an e-invoice (plain PDF, other XML, unreadable file), download failed, malformed input |

### Input

```json
{"url": "https://example.com/invoices/INV-2026-001.xml"}
```

```json
{"xml": "<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\" ...>...</Invoice>", "profile": "xrechnung"}
```

```json
{"invoices": [{"url": "https://example.com/a.pdf"}, {"file_base64": "PD94bWwg...", "name": "INV-7.xml"}]}
```

Up to 100 invoices per run; files up to 25 MB (invoice XML up to 10 MB). `profile`: `auto` (default), `en16931`,
`peppol`, `xrechnung`, `all`.

### Output (one item per invoice; the Peppol BIS example invoice with its amount due changed to 9999.00, shortened)

```json
{
  "index": 0,
  "source": "base-example.xml",
  "verdict": "BLOCK",
  "valid": false,
  "status": "checked",
  "syntax": "UBL 2.1 Invoice",
  "customization_id": "urn:cen.eu:en16931:2017#compliant#urn:fdc:peppol.eu:2017:poacc:billing:3.0",
  "standards": ["EN 16931", "Peppol BIS Billing 3.0"],
  "reasons": ["1 error(s) against EN 16931, Peppol BIS Billing 3.0; first: BR-CO-16 [BR-CO-16]-Amount due for payment (BT-115) = Invoice total amount with VAT (BT-112) -Paid amount (BT-113) +Rounding amount (BT-114)."],
  "error_count": 1,
  "warning_count": 0,
  "errors": [{"rule": "BR-CO-16", "severity": "error", "message": "[BR-CO-16]-Amount due for payment (BT-115) = …",
              "location": "/*:Invoice[…]/*:LegalMonetaryTotal[1]", "rule_set": "en16931-ubl"}],
  "warnings": [],
  "summary": {"number": "Snippet1", "type_code": "380", "issue_date": "2017-11-13", "currency": "EUR",
              "seller": {"name": "SupplierOfficialName Ltd", "vat_id": "GB1232434", "country": "GB"},
              "buyer": {"name": "Buyer Official Name", "vat_id": "SE4598375937", "reference": "0150abc"},
              "totals": {"net": "1325", "tax": "331.25", "gross": "1656.25", "payable": "9999.00"},
              "due_date": "2017-12-01", "ibans": ["IBAN32423940"], "lines": 2},
  "rules_version": {"en16931": "1.3.17", "xrechnung": "XRechnung 3.0.2 / config 2026-08-31", "peppol_bis_billing": "3.0.21", "ubl": "2.1", "cii": "D16B"}
}
```

For a Factur-X / ZUGFeRD PDF the item also has `facturx` (profile) and `container` (embedded file name, the PDF's
XMP `ConformanceLevel`, attachments). A mismatch between the PDF metadata and the XML profile is a warning.

### Scope and limits

- **Official rules, current versions:** EN 16931 validation artefacts 1.3.17, Peppol BIS Billing 3.0.21, XRechnung
  3.0.2 (KoSIT configuration 2026-08-31). Each result shows the versions in `rules_version`. The rules are pinned
  and checksum-verified when the Actor is built; nothing is downloaded during your run.
- **Factur-X/ZUGFeRD EXTENDED** is a declared superset of EN 16931: the CII rules that only restrict elements to
  the EN 16931 core (`CII-DT-*`, `CII-SR-*`) are shown as warnings for EXTENDED; business rules still apply.
- **PDF/A-3 conformance** of a Factur-X PDF is not checked (`container.pdfa_checked: false`), and the visible PDF
  is not compared with the XML: the XML is the legal invoice.
- **Not checked here:** whether the seller's VAT number is registered, the IBAN belongs to the seller, or the buyer
  is reachable on Peppol. [Payee Check](https://apify.com/lerider/payee-check) does that (IBAN, VIES, Peppol, invoice
  maths) in one call.
- Validation follows the published rules; it is not tax or legal advice.

Files are processed in memory for your run only; nothing is stored beyond your run's dataset.

### Related

- [Payee Check](https://apify.com/lerider/payee-check): IBAN, VAT, Peppol and invoice checks before paying a supplier
- [eIDAS Signature Validator](https://apify.com/lerider/eidas-signature-check): signed PDFs and XML against the EU trusted lists
- [EU VAT Validator](https://apify.com/lerider/eu-vat-validator) · [EORI Validator](https://apify.com/lerider/eori-validator) · [EU TIN Validator](https://apify.com/lerider/eu-tin-validator)

Made by Lerider Technologies (lerider.com).

# Changelog

This Actor's version history is a separate document: https://apify.com/lerider/einvoice-validator/changelog.md

# Actor input Schema

## `url` (type: `string`):

Link to an e-invoice: UBL 2.1 or CII XML (XRechnung, Peppol BIS, EN 16931) or a Factur-X / ZUGFeRD PDF (max 25 MB). Leave empty when you use another field.

## `file_base64` (type: `string`):

The invoice file (XML or Factur-X/ZUGFeRD PDF) as base64, instead of a URL.

## `xml` (type: `string`):

The invoice XML pasted as text, instead of a URL.

## `profile` (type: `string`):

Which rules to apply. Auto reads the invoice's specification identifier: EN 16931 always, plus Peppol BIS Billing 3.0 or XRechnung 3.0 when the invoice declares them.

## `invoices` (type: `array`):

Up to 100 per run: \[{"url": "..."}, {"file_base64": "...", "name": "INV-1.pdf"}, {"xml": "\<Invoice ...>"}]. Clear 'Invoice URL' when you use this.

## Actor input object example

```json
{
  "url": "https://raw.githubusercontent.com/OpenPEPPOL/peppol-bis-invoice-3/master/rules/examples/base-example.xml",
  "profile": "auto"
}
```

# Actor output Schema

## `results` (type: `string`):

No description

## `overview` (type: `string`):

No description

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "url": "https://raw.githubusercontent.com/OpenPEPPOL/peppol-bis-invoice-3/master/rules/examples/base-example.xml"
};

// Run the Actor and wait for it to finish
const run = await client.actor("lerider/einvoice-validator").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "url": "https://raw.githubusercontent.com/OpenPEPPOL/peppol-bis-invoice-3/master/rules/examples/base-example.xml" }

# Run the Actor and wait for it to finish
run = client.actor("lerider/einvoice-validator").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "url": "https://raw.githubusercontent.com/OpenPEPPOL/peppol-bis-invoice-3/master/rules/examples/base-example.xml"
}' |
apify call lerider/einvoice-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,lerider/einvoice-validator"
        }
    }
}
```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/ZHEuCBAgCWQRvb1jP/builds/AmOUktzHEJqh2Kppc/openapi.json
