Skip to main content

einvoicekit

Validate any EN 16931 e-invoice (Factur-X, ZUGFeRD, XRechnung, UBL or CII) against the full official rule set, from one command or one function call. No Java, no Saxon, no rule files to download.

pipx run einvoicekit invoice.pdf
invoice.pdf  INVALID  (cii, urn:cen.eu:en16931:2017)
  BR-CO-15  /Q{urn:un:unece:uncefact:data:standard:CrossIndustryInvoice:100}CrossIndustryInvoice[1]
            [BR-CO-15]-Invoice total amount with VAT (BT-112) = Invoice total amount without VAT (BT-109) + Invoice total VAT amount (BT-110).

Exit code 0 means every file is valid, 1 means at least one is not, 2 means at least one could not be validated. That is the whole integration for a CI pipeline.

What this package is, honestly

It is a thin client. Each call sends the invoice over HTTPS to einvoicekit's validator, which processes it in memory to produce the verdict and drops it; nothing is stored. What you get in exchange is the real thing: the official rule sets, EN 16931, XRechnung 3.0.2, Factur-X 1.09 and Peppol BIS 3.0, run by the reference validator, not a hand-written subset of them.

Two promises follow from that:

  • A verdict is a verdict. valid=False lists every broken rule with its official id, the official message and the XPath of the element at fault.
  • No silent green. If the service cannot be reached, you get an exception, never valid=True. The package has no fallback and no retry; a retry policy is yours to write.

Install

pip install einvoicekit

Python 3.10 or later. No dependencies.

Renamed in 0.2.0: the command was facturx and the error class FacturxError. The package name and the import name are unchanged.

Use it from code

from einvoicekit import validate, EinvoicekitError

with open("invoice.pdf", "rb") as f:
    result = validate(f.read())

result.valid  # True or False
result.errors  # [Finding(rule, message, path), ...]
result.warnings  # same shape, never change the verdict
result.syntax  # 'cii' or 'ubl'
result.profile  # the profile URN the document declares, or None
result.raw  # the API's JSON as a dict, untouched

validate(data, ...) takes the bytes of an XML invoice, or of a Factur-X / ZUGFeRD PDF, which is unwrapped first so its embedded XML is what gets validated. The result carries the API's JSON, field for field.

Keyword arguments:

argument meaning
api_key an einvoicekit key; defaults to EINVOICEKIT_API_KEY; with neither, the free pool is used
target "france" adds the BR-FR rules French platforms apply, opt-in per call
base_url the API to call, default https://api.einvoicekit.com
timeout seconds to wait for the answer, default 30

Use it from the command line

einvoicekit invoice.pdf
einvoicekit a.xml b.pdf --target france
einvoicekit invoice.pdf --json
einvoicekit invoice.pdf --warnings
EINVOICEKIT_API_KEY=eik_live_... einvoicekit invoice.pdf

--json prints the API's verdict as JSON on stdout, an array when several files are given, and nothing else there; refusals go to stderr. --help lists every option.

Limits, plainly

  • Without a key: 10 validations a day per IP address, shared with the free tools on einvoicekit.com. The eleventh call is refused with the time the pool resets (midnight UTC) and a link to the free key.
  • With a free key: 100 validations a month, plus 20 generated invoices in an allowance of their own. No card. Get one by signing in with GitHub.
  • Pro: 29 € a month for 1,000 pooled credits, a validation spending one. Details.

Only a delivered verdict counts. A document the API cannot assess, a refused call and an error on the service's side cost nothing.

Errors

Everything that is not a verdict raises EinvoicekitError with a stable code:

code HTTP meaning
bad_request 400 the request itself was wrong (bad target, empty body)
unauthorized 401 a key was sent and it is unknown, malformed or disabled
too_large 413 over 5 MB
unreadable_document 422 the API read the file and cannot assess it: a plain PDF, an unsupported profile
pool_exhausted 429 the free daily pool is spent; resets_at and upgrade say when and where
rate_limited 429 too many calls in a short window; slow down
quota_exceeded 429 the key's monthly allowance is spent; upgrade says where to get more
service_unavailable 5xx the service answered but could not validate
network 0 no response at all

A wrong key is never a fallback into the free pool: send no key at all to use it.

Scope

Validation checks the invoice XML: the schema and every business rule of the profile the document declares. It does not check the PDF container's own PDF/A conformance; that check runs on the generation side of the API.

Full API documentation, the French rules and the generation endpoint: einvoicekit.com/docs.

Licence

MIT.

Release files for einvoicekit 0.2.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for einvoicekit 0.2.0
File Size Uploaded
einvoicekit-0.2.0.tar.gz 13.6 kB Details

Built distribution (wheel)

Table of built distributions (wheels) for einvoicekit 0.2.0
File Interpreter ABI Platform
einvoicekit-0.2.0-py3-none-any.whl Python 3 none any Details

Total release size: 24.7 kB

Release files / einvoicekit-0.2.0.tar.gz

Download URL einvoicekit-0.2.0.tar.gz
Size 13.6 kB
Tags Source
SHA-256 checksum
How to use checksums
bf46e5a13ba8e23d36ca91eca0b1ac12719406dabb85070b9da52e08d61ea41d
BLAKE2b-256 checksum
How to use checksums
755a47d879ec0304fe506cede04af40e311527546d645db11e0bd54ec17af845
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.

Transparency log

Release files / einvoicekit-0.2.0-py3-none-any.whl

Download URL einvoicekit-0.2.0-py3-none-any.whl
Size 11.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
ca0a2127f81c589c6fefa702afaa450bdc0caac9cf863472175f0b2a54e2844e
BLAKE2b-256 checksum
How to use checksums
6f2a6d16bba968b3c97cd6de9a1c53d37953dc49a26e50c99d198b8314ef5a16
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Sep 4, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.2.0 This release

2 release files

0.1.1

2 release 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