Skip to main content

xmlvalid for Python

Python client for the xmlvalid API: validate XML documents and e-invoices against XSD, DTD, RelaxNG and Schematron business rules. Peppol BIS, XRechnung, Factur-X / ZUGFeRD, EN 16931, UBL, CII and national rules (France, Italy, Croatia, Romania and more) are in the schema catalog; your own schemas work too.

  • Python 3.10+, sync and async (asyncio, trio), built on httpx
  • Large files are streamed, not loaded into memory
  • Waits for the result for you, retries when rate limited
  • Typed results and exceptions, webhook signature checks

Install

pip install xmlvalid

Create an API key under Dashboard → API keys.

Validate

from xmlvalid import Client

xmlvalid = Client("xv_…")  # or set XMLVALID_API_KEY

validation = xmlvalid.validate("invoice.xml", schema="peppol-bis-3-invoice")

if validation.is_valid:
    print("Valid")
else:
    for error in validation.errors:
        print(error)  # Line 139: [BR-CO-16] Amount due for payment (BT-115) = …

The document can be:

xmlvalid.validate("invoice.xml")  # a path (XML, .gz, .zip, EPUB, Factur-X PDF)
xmlvalid.validate(Path("invoice.xml"))  # a Path
xmlvalid.validate(data, name="invoice.xml")  # bytes
xmlvalid.validate(open("invoice.xml", "rb"))  # a binary file object
xmlvalid.validate(text="<Invoice>…</Invoice>")  # a string
xmlvalid.validate(url="https://example.com/feed.xml")  # a public URL, downloaded by xmlvalid

The schema:

Argument Validates against
schema="peppol-bis-3-invoice" A catalog entry, with its business rules
schema="auto" The catalog profile an e-invoice names (BT-24), for mixed invoices
schema="my-12" One of your saved schemas
schema_file="order.xsd" An XSD, DTD or RelaxNG file sent with the document
doctype=True The DOCTYPE the document declares
none Well-formedness only

Your own Schematron runs after the schema check: rules="rules.sch", or for rules with includes, relative path: file: rules={"main.sch": "/path/main.sch", "parts/totals.sch": "/path/parts/totals.sch"}.

Async

from xmlvalid import AsyncClient

async with AsyncClient() as xmlvalid:
    validation = await xmlvalid.validate("invoice.xml", schema="xrechnung-3-ubl")

Every method of Client is there, awaited.

The result

validation.status  # done, failed (on xmlvalid's side) or cancelled
validation.result.outcome  # valid, warnings, invalid, schema, input or failed
validation.result.errors_total  # all of them; the first 500 are listed
for error in validation.errors:
    error.line, error.column, error.level, error.type  # xsd, schematron, …
    error.rule  # BR-CO-16 for a business rule
    error.message
    error.rule_url  # the rule's page on xmlvalid.com
    error.help_url  # how to fix this kind of error
validation.warnings
validation.raw  # the API's JSON, as a dict

For a .zip, validation.result.items has one result per document; for a PDF, validation.result.pdf names the invoice found in it.

Long validations, reports and the account

validate() waits up to 15 minutes (timeout=); a ValidationTimeoutError carries the validation, which goes on on the server. To queue and come back later:

validation = xmlvalid.submit("big.xml", schema="ubl-2.1-invoice")
# …
validation = xmlvalid.wait_for(validation.id)  # or xmlvalid.validation(id), xmlvalid.cancel(id)

html = xmlvalid.report(validation)  # the HTML report
link = xmlvalid.share([validation])  # a public link for 30 days (Pro): link.url

usage = xmlvalid.usage()  # usage.used, usage.limit, usage.remaining
schemas = xmlvalid.schemas()  # your saved schemas, then the catalog

Errors

Every exception extends xmlvalid.XmlvalidError. API refusals are ApiErrors with status_code, error_code and, for invalid_request, fields:

Exception When
AuthenticationError 401: no key, a revoked key
PlanLimitError 403: not in your plan
NotFoundError 404: no such validation, or it expired (24 hours)
NotFinishedError 409: the report of a validation still running
DocumentTooLargeError 413: over your plan's size limit
InvalidRequestError 422: unknown schema, a bad URL, …
QuotaExceededError 429: this month's validations are used up
RateLimitedError 429: still limited after the retries; retry_after seconds
ServerError 5xx
TransportError The request could not be sent or its answer read
ValidationTimeoutError Still running after timeout= (also a TimeoutError)

Webhooks

On Pro, xmlvalid can call your endpoint when a validation finishes or a URL monitor changes state. Check the signature with the endpoint's secret and the raw body:

from xmlvalid import Event, webhooks

event = webhooks.verify(
    request.body,  # the raw bytes, as received
    request.headers.get("Xmlvalid-Signature"),
    os.environ["XMLVALID_WEBHOOK_SECRET"],
)  # raises SignatureVerificationError

if event.type == Event.VALIDATION_COMPLETED:
    validation = event.validation

A retried delivery has the same event.id. The other events are monitor.failed, monitor.recovered (event.data["monitor"], event.data["check"]) and ping.

Options

Client(
    api_key="xv_…",  # default: XMLVALID_API_KEY
    base_url="https://xmlvalid.com/api/v1",
    timeout=900,  # seconds validate() waits in all
    wait=10,  # seconds the API holds a new request (0-60)
    max_retries=3,  # retries of a 429 rate_limited
    http_client=httpx.Client(...),  # proxies, certificates, a mock transport in tests
)

Use it as a context manager, or call close(), to close the connection pool.

Development

uv sync
uv run pytest
uv run mypy
uv run ruff check && uv run ruff format --check

License

MIT

Metadata

Release files for xmlvalid 1.0.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 xmlvalid 1.0.0
File Size Uploaded Provenance
xmlvalid-1.0.0.tar.gz 21.8 kB Without provenance Details

Built distribution (wheel)

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

Total release size: 39.2 kB

Release files / xmlvalid-1.0.0.tar.gz

Download URL xmlvalid-1.0.0.tar.gz
Size 21.8 kB
Tags Source
SHA-256 checksum
How to use checksums
911dd662e2d08bc99cd7c4277b6fd909e883f25067767a5fda12a37b99931b39
BLAKE2b-256 checksum
How to use checksums
90ee48d9d1c82c201ee4cc1a51bf396dbe17b471c7a8abf12d9ff92d7bbd2ded
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / xmlvalid-1.0.0-py3-none-any.whl

Download URL xmlvalid-1.0.0-py3-none-any.whl
Size 17.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
a66ca69882c4315ab8284a75f7a144ebd2e3c548a97eb76ea11b86e585307981
BLAKE2b-256 checksum
How to use checksums
f2567023176cc8c22de56fa9561a396454aa10fe03859dc21f2aa094f53e0ac7
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.13.1 {"installer":{"name":"uv","version":"0.13.1","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for xmlvalid 1.0.0

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.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

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