Send-readiness & fixing violations
Before TaxLens lets you export or issue an invoice, it runs a pre-check: a single gate that verifies every mandatory field is present and the totals reconcile. If something's missing, you get an HTTP 422 with the exact list of what to fix.
One gate, used everywhere
The pre-check lives in app/services/einvoice_validation.py and is the single source of truth for send-readiness. The same code runs in three places, so they can never disagree:
GET …/documentreturns avalidationblock (is_valid+violations[]) so you can preview readiness.GET …/document/ublblocks export with HTTP 422 if the document isn't valid.POST …/issueruns it one final time before burning a fiscal number.
What it checks
The mandatory Business Terms fall into three buckets — seller, buyer, and document:
| Field | Type | Description |
|---|---|---|
| Seller namerequired | BT-27 | The legal entity issuing the invoice. Comes from the legal issuer. |
| Seller countryrequired | BT-40 | The issuer's registered country. |
| Seller VAT / tax registrationrequired | BT-31 | At least one tax registration on the issuer. Add it under Legal issuers. |
| Seller PEPPOL endpointrequired | BT-34 | Endpoint id and EAS scheme — how the issuer is addressed on PEPPOL. |
| Buyer namerequired | BT-44 | Set via buyer_name on the booking or PATCH invoice-details. |
| Buyer postal countryrequired | BT-55 | The country in the buyer's address. |
| Buyer VAT id | BT-48 | Required only when the invoice carries a reverse-charge (AE) line. |
| Currencyrequired | BT-5 | The document currency. |
| VAT lines + per-rate subtotalsrequired | BG-23 | At least one VAT line; every standard-rated line carries a rate > 0; each VAT category has a matching tax subtotal that reconciles. |
B2B (business buyer) also requires
When the buyer is a business (customer_type='business'), an Access Point needs a few extra Business Terms before it will route the invoice. These rules apply only to business buyers — a consumer (B2C) invoice that clears the table above is already send-ready:
| Field | Type | Description |
|---|---|---|
| Buyer reference / PO referencerequired | BT-10 | A routing reference for the buyer (PEPPOL-EN16931-R003). Set buyer_reference on the booking or via PATCH invoice-details. |
| Buyer electronic address + EAS schemerequired | BT-49 | The PEPPOL endpoint the network delivers to (PEPPOL-EN16931-R010) — an endpoint id plus a 4-digit EAS/ICD scheme code. Set buyer_endpoint_id and its scheme. |
| Payment terms / due daterequired | BT-20 | When the payable amount is positive, the invoice needs payment terms (BT-20) or a due date (BT-9) — BR-CO-25. |
What a blocked export looks like
When the document isn't send-ready, the UBL endpoint refuses with HTTP 422 and lists each violation by Business Term, so you know exactly what to set:
{
"detail": {
"message": "Booking is not PEPPOL send-ready. Resolve the listed violations and try again.",
"violations": [
{ "code": "BT-31", "severity": "error", "field": "BT-31",
"message": "Seller VAT/tax registration is required." },
{ "code": "BT-44", "severity": "error", "field": "BT-44",
"message": "Buyer name is required. Pass buyer_name when creating the booking." },
{ "code": "BT-55", "severity": "error", "field": "BT-55",
"message": "Buyer postal address country code is required. Pass buyer_address.country_code when creating the booking." }
]
}
}LODGING-OCCUPANCY-TAX-EXCLUDED) — those levies are excluded from the e-invoice by design, not an error. See VAT-only invoices.How to clear the violations
- 1Configure the seller (once per org)In Settings, create a legal issuer with its legal name and country, add at least one tax registration (BT-31), and set its PEPPOL endpoint id + scheme (BT-34). This clears every seller-side violation for all future invoices.
- 2Attach the issuer to the bookingSet
legal_issuer_idwhen you create the booking, or later via PATCH invoice-details. Properties can default it (default_legal_issuer_id) so bookings inherit the right seller. - 3Capture the buyerProvide
buyer_nameand abuyer_addresswith at least a country. The dashboard's "Edit invoice details" form does this without re-running the tax engine. - 4Re-checkCall
GET …/documentagain and confirmvalidation.is_validistrue. Now the UBL export and issuance succeed.
// PATCH /v1/bookings/4821/invoice-details
{
"legal_issuer_id": 7,
"buyer_name": "Northwind Travel GmbH",
"buyer_address": { "city": "Berlin", "country_code": "DE" }
}Next
With a green pre-check you're ready to run the full invoice lifecycle. For the field-by-field API reference, see E-invoicing (API), and for common stumbles, Troubleshooting.