Skip to main content

Python client SDK for the Xingen e-invoice validation API

Project description

xingen

Python client SDK for the Xingen e-invoice validation API — submit UBL, CII, ZUGFeRD, and SAP IDoc/OData invoices for validation against EN16931, XRechnung, and Peppol.

Requires Python 3.10+. Built on requests and pydantic v2.

Status: v1, covering invoice submission/validation and API key management. Contacts and dashboard/user endpoints are not exposed (they're Firebase-auth-only on the backend).

Install

pip install xingen-sdk

(The distribution is named xingen-sdk on PyPI since xingen was already taken by an unrelated project, but the import name is still xingen: from xingen import XingenClient.)

Authentication

Every request needs an API key (xgn_live_... for production, xgn_test_... for sandbox — sandbox requests never count toward quota). Create one from the Xingen dashboard or via client.api_keys.

from xingen import XingenClient

client = XingenClient(api_key=os.environ["XINGEN_API_KEY"])

XingenClient holds one connection-pooled requests.Session — construct it once and reuse it, don't rebuild it per request. base_url=... overrides the default https://app.xingen.de/api, useful for self-hosted or local (./gradlew bootRun, port 10001) testing.

Validate a file

Every validate/submit endpoint is asynchronous — the backend queues the invoice and returns immediately. Use a *_and_wait helper to submit and poll for the result in one call:

from xingen.models.enums import InvoiceStatus, ValidationProfile

result = client.invoices.validate_file_and_wait("invoice.xml", ValidationProfile.XRECHNUNG)

if result.status is InvoiceStatus.VALIDATED and result.validation_result.valid:
    print("Valid!")
else:
    for error in result.validation_result.errors:
        print(f"{error.severity}: {error.message} ({error.field})")

PollOptions controls the backoff (initial_interval, max_interval, backoff_multiplier), the overall timeout, and an optional cancellation_check. A failed validation is not an exception — it's a completed API call that found the invoice invalid, so *_and_wait returns normally with validation_result.valid == False. Only a transport failure, cancellation, or timeout raises.

from xingen.invoices import PollOptions

options = PollOptions(initial_interval=0.3, max_interval=3.0, timeout=30.0)
result = client.invoices.validate_file_and_wait("invoice.xml", ValidationProfile.XRECHNUNG, options)

If you'd rather manage polling yourself, use the low-level pair:

submitted = client.invoices.validate_file("invoice.xml", ValidationProfile.EN16931)
# ... later ...
record = client.invoices.get(submitted.id)

validate_idoc / validate_idoc_and_wait work the same way for SAP IDoc XML files. Both, and validate_file/validate_file_and_wait, also accept (filename, content_bytes) tuples if you already hold the file bytes in memory instead of a path.

Submit a structured invoice (JSON)

from datetime import date
from decimal import Decimal

from xingen.invoices import InvoiceSubmission, LineInput, PartyInput

submission = InvoiceSubmission(
    invoice_number="INV-2024-0042",
    issue_date=date(2024, 3, 15),
    currency="EUR",
    buyer_reference="991-12345-06",
    validation_profile=ValidationProfile.XRECHNUNG,
    supplier=PartyInput(name="Acme GmbH", vat_id="DE123456789"),
    buyer=PartyInput(name="Buyer Co", leitweg_id="991-12345-06"),
    lines=[
        LineInput(
            description="Software License Q1",
            quantity=Decimal("5"),
            unit="C62",
            price=Decimal("199.00"),
            tax_rate=Decimal("19"),
        )
    ],
)

result = client.invoices.submit_and_wait(submission)

SAP S/4HANA OData supplier-invoice payloads are supported as a thin passthrough — pass raw JSON or a dict rather than a fully typed model:

client.invoices.submit_odata(raw_odata_json, ValidationProfile.EN16931)

List and retrieve invoices

page = client.invoices.list(0, 20, "createdAt,desc")

# or, to walk every invoice without managing page indices yourself:
for record in client.invoices.list_all(50):
    print(record.id, "->", record.status)

one = client.invoices.get("inv_01HXYZ")

Download results

pdf = client.invoices.download_pdf(id)          # ZUGFeRD PDF with embedded XML
idoc_xml = client.invoices.download_idoc_xml(id)  # SAP IDoc XML

API keys

from xingen.apikeys import CreateApiKeyRequest

created = client.api_keys.create(CreateApiKeyRequest(name="Production CI", sandbox=False))
print("Store this now, it's shown only once:", created.raw_key)

keys = client.api_keys.list()
client.api_keys.revoke(created.id)

Error handling

All SDK exceptions extend XingenException. HTTP errors map to typed subclasses of ApiException:

Exception Status Notes
AuthenticationException 401 Missing or invalid API key
PermissionException 403 Resource exists but isn't owned by the caller
NotFoundException 404
ValidationRequestException 400 .field_errors has details for request-body validation failures
QuotaExceededException 429 Monthly request quota exhausted
ApiException other 4xx/5xx Fallback; .status_code / .raw_body always available
from xingen.error import QuotaExceededException, ValidationRequestException, XingenException

try:
    client.invoices.submit(submission)
except ValidationRequestException as e:
    for field, message in e.field_errors.items():
        print(f"{field}: {message}")
except QuotaExceededException:
    print("Quota exceeded — upgrade or wait for the next billing period")
except XingenException as e:
    print(f"Request failed: {e}")

Design notes

  • No automatic retries. Retrying a submit() after a client-side timeout is unsafe without idempotency keys, which the API doesn't support yet — a retried submit could create a duplicate invoice. Handle retries at the call site if you need them.
  • Monetary and quantity fields are Decimal, never float. JSON is parsed through Python's stdlib json module with parse_float=Decimal rather than pydantic's native (float64-lossy) JSON parser, so exact literal precision is preserved end to end.

Contributing

pip install -e ".[dev]"
ruff check .
mypy src/xingen
pytest

Tests run against a real (loopback) http.server.HTTPServer, not a mocking framework — no network calls leave the machine, and no external test-server dependency is required.

License

MIT — see LICENSE.

Project details


Download files

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

Source Distribution

xingen_sdk-0.1.0.tar.gz (22.8 kB view details)

Uploaded Source

Built Distribution

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

xingen_sdk-0.1.0-py3-none-any.whl (21.5 kB view details)

Uploaded Python 3

File details

Details for the file xingen_sdk-0.1.0.tar.gz.

File metadata

  • Download URL: xingen_sdk-0.1.0.tar.gz
  • Upload date:
  • Size: 22.8 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for xingen_sdk-0.1.0.tar.gz
Algorithm Hash digest
SHA256 b39d85939092890d94c596f44f74d40817b38f97bc311de8e50ea4812895133d
MD5 34129274264b0136aa6031a777b60839
BLAKE2b-256 bed5fc57da2278f76823a277c443c6b4997f4c7c0d67b0bb6de3e5b49554ef9a

See more details on using hashes here.

Provenance

The following attestation bundles were made for xingen_sdk-0.1.0.tar.gz:

Publisher: publish.yml on nko-technologies/xingen-python-sdk

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

File details

Details for the file xingen_sdk-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: xingen_sdk-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 21.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for xingen_sdk-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 1888edcfa37b143ece4c9bae3fd8d4c802d44d853c742bd3ee4fa365a8110f00
MD5 85ff518603494ae79994b55f876c62f8
BLAKE2b-256 627942da227300ed71570e2d3c11508e47fa4ea4812ba484ebc1f3e227ebd55f

See more details on using hashes here.

Provenance

The following attestation bundles were made for xingen_sdk-0.1.0-py3-none-any.whl:

Publisher: publish.yml on nko-technologies/xingen-python-sdk

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

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page