Skip to main content

erechnung-core

PyPI Python versions Tests Coverage Licence

Deterministic German E-Rechnung generation and validation for Python.

Takes finalized invoice data, returns an XRechnung document that the official KoSIT validator accepts — plus a checksum, a normalized validation report, and the exact standard versions it was built with.

It is not an invoicing application. It has no opinion about invoice numbering, tax treatment, delivery, or archiving, and it never alters the values you give it. It is the piece you drop into software that already creates invoices.

pip install erechnung-core

Quick start

from erechnung_core import Invoice, KositValidator, process

invoice = Invoice.model_validate(payload)  # strict input contract
result = process(invoice, validator=KositValidator.from_manifest())

result.valid  # verified, generated, and officially validated
result.document.content  # XRechnung UBL bytes
result.document.sha256  # stable for identical input
result.validation.errors  # normalized, bilingual, rule-identified

Generating without validating needs no Java and no toolchain:

from erechnung_core import Invoice, process

result = process(Invoice.model_validate(payload))  # verify + generate only

Verifying the arithmetic without generating anything:

from erechnung_core import Invoice, verify

report = verify(Invoice.model_validate(payload))
report.valid
report.computed.tax_breakdown  # what the amounts should have been

Official validation

Validation runs the real KoSIT validator against the official XRechnung rule bundle. That toolchain is a Java archive with its own licence and release cadence, so it is not bundled in the wheel — it is downloaded on demand and checksum-verified against a manifest that ships inside the package:

erechnung-fetch-standards           # ~11 MB into ./validators/kosit
erechnung-fetch-standards --list    # manifests shipped with this version

Point it elsewhere with --target, or set ERECHNUNG_VALIDATOR_HOME and the library will find it. An artifact whose checksum does not match is deleted, not installed.

Java is required only for validation. If you have your own validator — hosted, cached, or a test double — implement DocumentValidator and pass it to process(); nothing else changes.

What it guarantees

Each of these is enforced by a test, not just documented:

  • Money never becomes a float. Amounts arrive as decimal strings; a float in the payload is a validation error, not a silent conversion.
  • Nothing is silently corrected. A supplied total that disagrees with the calculated one is reported with both values and the difference. The generator serializes what it was given.
  • Verification precedes generation. No document is produced from numbers that do not add up, unless you explicitly ask for one.
  • The official validator decides. A document that was not validated is never reported as valid; a missing toolchain raises rather than passes.
  • Generation is byte-stable. No timestamps, locale, or map ordering reach the output — which is what makes the stored checksum meaningful.
  • Standards are pinned data, not code. Every document records the standard, bundle, validator, and generator versions it was made with.
  • No LLM anywhere in the pipeline. Rule text is curated by hand.

Errors

Findings from every layer — input contract, arithmetic, XSD, Schematron — arrive in one shape, in English and German, keyed by rule identifier:

{
    "code": "BR-CO-16",
    "category": "CALCULATION",
    "severity": "error",
    "field": "invoice.totals.payable_amount",
    "message": "The payable amount does not equal the tax inclusive amount minus "
    "the prepaid amount plus the rounding amount.",
    "message_de": "Der Zahlbetrag entspricht nicht dem Gesamtbetrag mit "
    "Umsatzsteuer abzueglich des bereits gezahlten Betrags ...",
    "context": {"supplied": "1784.00", "calculated": "1784.94", "difference": "-0.94"},
}

Results separate errors, warnings, and notices, so a "should" rule never inflates the failure count and never disappears either.

Supported standards

XRechnung 3.0.2   bundle 2026-01-31, UBL 2.1 syntax          supported
                  urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0
KoSIT validator   1.6.2, configuration v2026-01-31           pinned
XRechnung CII                                                not yet
ZUGFeRD 2.5       EN16931 profile, PDF/A-3                   not yet

Covered today: standard and reduced rates, mixed rates on one invoice, reverse charge and other exemption categories, line and document allowances and charges, prepayments, service periods, SEPA credit transfer and direct debit with mandate, payee (factoring), delivery party and location, invoiced object and supporting document references, item identifiers, price discounts, and attachments.

Six golden fixtures cover these, and every one of them is checked against the official validator in CI on each change.

Requirements

Python 3.10 through 3.14, pydantic, and lxml. Nothing else. A Java runtime is needed only for official validation.

Every supported version is tested in CI, and all of them produce byte-identical documents — the checksum of a given invoice does not depend on the interpreter that generated it.

Development

uv sync                              # venv, dependencies, this package
uv run erechnung-fetch-standards     # validator toolchain
uv run pytest                        # 90 tests, ~45s
uv run pytest -m "not official"      # 76 tests, ~0.4s, no Java needed
uv run pytest --cov                  # with coverage

Checks:

uv run ruff check . && uv run ruff format . && uv run mypy erechnung_core

Install the hooks with uv run pre-commit install to run the same checks before each commit.

Golden fixtures live in fixtures/scenarios/. Each holds an input.json and the expected-xrechnung.xml it must produce byte for byte; all of them are additionally run through the official validator in CI. A change that alters generated output shows up as a failing golden test, which is the point.

erechnung_core/
  canonical/       EN 16931 input contract
  calculations/    independent recalculation and comparison
  xrechnung/       UBL 2.1 serializer
  validation/      KoSIT wrapper, validator protocol
  error_mapping/   curated bilingual rule catalogue
  data/            pinned standards manifests (shipped in the wheel)
  pipeline.py      verify -> generate -> validate
fixtures/          golden scenarios
tests/             unit tests and official-validator tests

Scope

Deliberately excluded: invoice editing, customer and product management, email or Peppol delivery, DATEV, bookkeeping, long-term archiving, OCR, and PDF-to- invoice extraction. Those belong to the application using this library.

Contributing

See CONTRIBUTING.md. Bug reports that include a minimal anonymised invoice and the official validator's verdict are the most useful. Security issues go through SECURITY.md, never a public issue.

Licence

Apache-2.0. See LICENSE and CHANGELOG.md.

Technical validity is not fiscal correctness. This library checks that a document conforms to EN 16931 and XRechnung rules and that its arithmetic is self-consistent. It cannot tell whether the VAT treatment is right. Whoever supplies the data remains responsible for its commercial, legal, and tax accuracy, and for pinning a bundle version appropriate to the period being invoiced. Provided without warranty; this is not tax or legal advice.

Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

erechnung_core-1.0.0.tar.gz (47.0 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

erechnung_core-1.0.0-py3-none-any.whl (41.9 kB view details)

Uploaded Python 3

File details

Details for the file erechnung_core-1.0.0.tar.gz.

File metadata

  • Download URL: erechnung_core-1.0.0.tar.gz
  • Upload date:
  • Size: 47.0 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for erechnung_core-1.0.0.tar.gz
Algorithm Hash digest
SHA256 3a3b98493111cfcc643863bacce6c43951c7a8234f23bb962baa61d1e54b6281
MD5 2aac3755f8c7313277727f6f34b97a24
BLAKE2b-256 2e61fe287c80bac4f223cd589baffc852f526ed9b0d1f0d98f5abe565ee545b7

See more details on using hashes here.

Provenance

The following attestation bundles were made for erechnung_core-1.0.0.tar.gz:

Publisher: publish.yml on shahidkarimi/erechnung-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file erechnung_core-1.0.0-py3-none-any.whl.

File metadata

  • Download URL: erechnung_core-1.0.0-py3-none-any.whl
  • Upload date:
  • Size: 41.9 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/7.0.0 CPython/3.13.14

File hashes

Hashes for erechnung_core-1.0.0-py3-none-any.whl
Algorithm Hash digest
SHA256 22037b5973372e103fbfb9c69f0a4b1622e0a3fb02857be2990be56f108e7b7b
MD5 ffde0fe32a96e3cdaac40d8d73f9e732
BLAKE2b-256 7f7a15d522c1ff4b58cf3b8f1d9fea738310d2bbad7158430e62428ec4c1e7ff

See more details on using hashes here.

Provenance

The following attestation bundles were made for erechnung_core-1.0.0-py3-none-any.whl:

Publisher: publish.yml on shahidkarimi/erechnung-core

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

1.0.0 This release

2 files

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page