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: boolcanonical: normalized invoice dict (all fields in canonical names)errors: list of blocking issues with rule_id, path, expected/actualwarnings: advisory issuesnormalizations: field-level provenance (what was renamed, coerced, computed)zugferd_ready: bool (ifzugferd=True)
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
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file trustrender-0.3.0.tar.gz.
File metadata
- Download URL: trustrender-0.3.0.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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
b94fa27d9c753ea0401717d8571eb97d22a1e965204f6104d227e9c922d8c460
|
|
| MD5 |
275755a4a0deab8c45c274a9a770e844
|
|
| BLAKE2b-256 |
f4a2a98d5daec34e7327b570ba5e451518a7386946d7b82c6cf6522f94c04e91
|
File details
Details for the file trustrender-0.3.0-py3-none-any.whl.
File metadata
- Download URL: trustrender-0.3.0-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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
f7ba02dc5617c37df7458064ca3cd963db5bc8e9d35e1e028d509a9e763c1072
|
|
| MD5 |
cd0ae7381cbce125ab61404b61fead11
|
|
| BLAKE2b-256 |
a6e81e4c31ae11cad26335cc15d36e0e9a3a173eb5df0c21d16efb02bc428496
|