Skip to main content

Validate and normalize Stripe, Shopify, and custom billing data for Factur-X/ZUGFeRD

Project description

TrustRender

Validate and normalize billing data from Stripe, Shopify, and custom systems before Factur-X/ZUGFeRD embedding.

If you're bridging a non-compliant billing platform into EU e-invoicing, libraries like factur-x and drafthorse assume your data is already correct. TrustRender catches arithmetic mismatches, field misalignment, missing required fields, and structural problems before compliant XML gets embedded.

pip install trustrender
trustrender validate invoice.json

What it does

Takes invoice JSON from Stripe, Shopify, custom billing APIs, or legacy exports and tells you whether it's safe to embed as Factur-X/ZUGFeRD.

$ trustrender validate quickbooks_invoice.json

Invoice:   INV-2026-5541
From:      Summit Analytics Co.
To:        Horizon Financial
Items:     2
Total:     $10,524.50

Normalizations (25):
  DocNumber → invoice_number        CompanyName → sender.name
  TxnDate → invoice_date            customer.Name → recipient.name
  Line → items                      SubTotal → subtotal
  ... and 19 more

PASS — invoice data is valid

Safe to embed in Factur-X/ZUGFeRD PDF.

Bad data gets blocked:

$ trustrender validate ocr_extracted_invoice.json

BLOCKED — 2 problem(s)

  items[1] total is wrong
    You entered $459.00 but math says $450.00
    Fix the line total or the price/quantity.

  Subtotal is wrong
    Lines add up to $12,459.00 but you listed $12,450.00

This invoice cannot be processed until the problems above are fixed.

Install

pip install trustrender

Core install requires only drafthorse. No Typst, no browser, no heavy deps.

Optional extras:

pip install "trustrender[zugferd]"    # XSD/Schematron validation
pip install "trustrender[render]"     # PDF rendering via Typst
pip install "trustrender[all]"        # everything

Requires Python 3.11+.

Python API

from trustrender import validate_invoice

result = validate_invoice({
    "invoiceNo": "INV-001",
    "vendor": {"companyName": "Acme Corp"},
    "customer": {"Name": "Client Inc"},
    "LineItems": [{"desc": "Widget", "qty": 2, "unitPrice": 50, "amount": 100}],
    "SubTotal": 100,
    "tax": 8.50,
    "TotalAmt": 108.50,
}, zugferd=True)

if result["render_ready"] and result.get("zugferd_ready"):
    # safe to call factur-x / drafthorse
    print("All checks passed")
else:
    for error in result["errors"]:
        print(f"BLOCKED: {error['message']}")

validate_invoice() returns:

  • status: "ready" | "ready_with_warnings" | "blocked"
  • render_ready: bool
  • canonical: normalized invoice dict (all fields in canonical names)
  • errors: list of blocking issues with rule_id, path, expected/actual
  • warnings: advisory issues
  • normalizations: field-level provenance (what was renamed, coerced, computed)
  • zugferd_ready: bool (if zugferd=True)

Stripe adapter

Raw Stripe Invoice API responses use cents, Unix timestamps, and nested structures. The adapter handles all of it:

trustrender validate stripe_invoice.json --source stripe --zugferd
from trustrender import validate_invoice
from trustrender.adapters import from_stripe

result = validate_invoice(from_stripe(raw_stripe_response), zugferd=True)

The adapter converts cents to dollars, timestamps to dates, extracts line items from lines.data[], and maps customer fields to recipient. Seller info is not included in Stripe invoices — TrustRender will flag it if required for ZUGFeRD compliance.

What it normalizes

90+ vendor field aliases across QuickBooks, Xero, Stripe, and generic CSV/ERP formats:

Source field Canonical field
DocNumber, invoiceNo, inv_no, ref invoice_number
CompanyName, account_name, bill_from_name sender.name
customer, billTo, Contact recipient
Line, LineItems, entries, products items
UnitPrice, cost, rate, unitCost unit_price
Amount, LineAmount, line_total line_total
SubTotal, net_total, sub_total subtotal
TotalAmt, grand_total, amount_due total

Plus: type coercion ("$1,234.56"1234.56), date parsing ("April 10, 2026"2026-04-10), computed defaults (missing line_total = qty × price), near-match typo detection (invioce_number → suggests invoice_number).

What it checks

7 deterministic semantic checks, all arithmetic:

Check What it catches
identity.invoice_number Missing or empty invoice number
identity.sender_name Missing vendor/sender name
identity.recipient_name Missing recipient/buyer name
items.non_empty No line items
arithmetic.line_total line_total ≠ qty × unit_price
arithmetic.subtotal subtotal ≠ sum of line_totals
arithmetic.total total ≠ subtotal + tax_amount

No AI. No heuristics. Every check is deterministic and objectively verifiable.

CLI

trustrender validate <data.json> [--zugferd] [--format text|json]
trustrender ingest <data.json> [-o canonical.json]
trustrender render <template> <data.json> -o <output.pdf> [--zugferd en16931]
trustrender preflight <template> <data.json> [--zugferd en16931]
trustrender serve --templates <dir> [--port 8190]
trustrender doctor [--smoke]

Integration with factur-x / drafthorse

TrustRender validates and normalizes. You generate and embed with the library of your choice.

from trustrender import validate_invoice

# Step 1: Validate with TrustRender
result = validate_invoice(messy_data, zugferd=True)
if not result["render_ready"] or not result["zugferd_ready"]:
    raise ValueError(f"Invoice blocked: {result['errors']}")

# Step 2: Use the canonical payload with drafthorse or factur-x
canonical = result["canonical"]
# ... your existing ZUGFeRD generation code here

EN 16931 e-invoicing (narrow scope)

Catches many document-level and ZUGFeRD/EN 16931 readiness issues before embedding. Currently supports:

  • Domestic German B2B invoices with standard VAT, EUR, SEPA payment
  • Single or mixed VAT rates (7% + 19%)
  • Invoice type 380 and credit note 381
  • PDF/A-3b with embedded CII XML (requires trustrender[render])

Not supported (fails loudly): reverse charge, cross-border, allowances/charges, non-EUR currencies.

See docs/einvoice-scope.md for the full scope matrix.

Optional: PDF rendering

If you also want TrustRender to generate PDFs (not just validate):

pip install "trustrender[render]"
trustrender render invoice.j2.typ data.json -o invoice.pdf --zugferd en16931

Rendering uses Typst — no browser, no Chromium. Fast and deterministic.

What this is not

  • Not a full AP automation platform
  • Not an e-invoice compliance certification
  • Not an AI-powered data fixer (all corrections are deterministic)
  • Not a replacement for factur-x or drafthorse — it's the validation layer you run before them

Development

pip install -e ".[dev]"
trustrender doctor --smoke
pytest

License

MIT

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

trustrender-0.3.1.tar.gz (1.8 MB view details)

Uploaded Source

Built Distribution

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

trustrender-0.3.1-py3-none-any.whl (1.7 MB view details)

Uploaded Python 3

File details

Details for the file trustrender-0.3.1.tar.gz.

File metadata

  • Download URL: trustrender-0.3.1.tar.gz
  • Upload date:
  • Size: 1.8 MB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for trustrender-0.3.1.tar.gz
Algorithm Hash digest
SHA256 02199b3e2b43212974734b84a1fe7c5c9e6002d2701fbdedfbc681f1b941a594
MD5 ecc2a4df74de6835c5e3cfa7dbf94152
BLAKE2b-256 e736580a1ff850f433c3d599cc99791e9d8208e5e2e069fcf0795a4b26ffb8b5

See more details on using hashes here.

File details

Details for the file trustrender-0.3.1-py3-none-any.whl.

File metadata

  • Download URL: trustrender-0.3.1-py3-none-any.whl
  • Upload date:
  • Size: 1.7 MB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.13

File hashes

Hashes for trustrender-0.3.1-py3-none-any.whl
Algorithm Hash digest
SHA256 cc40887371c16841fbce0d5a13156f5091ca608cdbe00649b426c1abab4e6e8c
MD5 acd105c6ff18288521c842613d6a8851
BLAKE2b-256 b409581a6b7ae80648d9f0f532cb54ddd1c55199d922255f9c0117ef75538231

See more details on using hashes here.

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