E-Invoicing Integrations
The einvoice module turns a posted customer invoice into a standardised EN 16931 /
Peppol BIS Billing 3.0 UBL document, validates it against the core business rules, and
transmits it through a certified Access Point provider. This page documents the
data contract a consultant configures and the provider seam a third party implements to
add a new Access Point — the same shape as the payment and
shipping provider hooks.
What it produces
Section titled “What it produces”For a FinancialDocument of type Customer Invoice, Credit Note, or Debit Note, the
module generates UBL 2.1 XML carrying the Peppol BIS Billing 3.0 customization. The tax
breakdown is derived from the invoice lines — one cac:TaxSubtotal per VAT category + rate —
even though the document stores only a single rolled-up tax total.
The invoice form gains an E-Invoicing tab (status, the generated XML, any validation errors) and three actions:
| Action | Method | Effect |
|---|---|---|
| Validate E-Invoice | action_validate_einvoice | Check the invoice against the core EN 16931 rules; surfaces what to fix. |
| Generate E-Invoice | action_generate_einvoice | Validate, then build and store the Peppol BIS UBL. |
| Send E-Invoice | action_send_einvoice | Generate if needed, then transmit through the configured Access Point. |
Data a consultant configures
Section titled “Data a consultant configures”The document is only transmittable when both parties are addressable on the network and the tax data is complete:
| Field | On | Meaning |
|---|---|---|
peppol_endpoint_id + peppol_scheme | Company, Contact | The party’s electronic address on the Peppol network (usually the VAT number or a GLN) and its EAS scheme code (e.g. 9930 = DE VAT, 0088 = GLN). |
tax_number | Company, Contact | The VAT identifier (already part of core). Required on the seller when VAT is charged. |
vat_category | Tax | The EN 16931 VAT category (Standard Rate / Zero Rated / Exempt / Reverse Charge / …). Maps to the UNCL5305 code (S/Z/edit/AE/…) on the wire. |
exemption_reason | Tax | Required by EN 16931 for any non-standard category. |
action_validate_einvoice reports missing or inconsistent values in these terms (e.g.
“Buyer Peppol endpoint ID / scheme is missing”) so they can be fixed before sending.
The Access Point provider seam
Section titled “The Access Point provider seam”Peppol uses a 4-corner model: your install is Corner 1 (the sender); the Access Point provider is Corner 2 and handles the AS4 transport plus SML/SMP discovery to reach the recipient’s Access Point (Corner 3) and the recipient (Corner 4). You never operate an Access Point yourself — you connect to a certified provider’s API.
A provider is a module that extends Integration (with integration_category: E-Invoicing in its manifest so it appears in the Integrations catalog) and overrides the
transmission hooks, guarding on its own provider check and delegating to super() for the
rest — exactly the payment/shipping pattern:
class MyApProvider(Model): __inherit__ = "Integration"
async def send_einvoice(self, document, xml_bytes, doc_format): if not await self._is_my_ap(): return await super().send_einvoice(document, xml_bytes, doc_format) # ... POST xml_bytes to the Access Point's API ... return {"message_id": "<ap-ref>", "state": "Sent"} # or "Delivered" / "Rejected"The hooks a provider may implement (the base raises NotImplementedError, so an invoice can
always be generated and validated locally even with no provider connected):
| Hook | Purpose | Returns |
|---|---|---|
send_einvoice(document, xml_bytes, doc_format) | Transmit a generated e-invoice (Corner 2). | {"message_id", "state"} |
fetch_einvoice_status(message_id) | Poll delivery status of a sent document. | {"state", "detail"} |
validate_einvoice(xml_bytes, doc_format) | Optional provider-side Schematron validation (the full ~200-rule EN 16931 set). | {"valid", "errors": [...]} |
receive_einvoices() | Inbound (Corner 4): fetch e-invoices delivered to you. | [{"message_id", "xml", "sender", "received_at"}] |
The enabled provider is resolved with Integration.resolve_einvoice_provider() (the first
enabled E-Invoicing integration).
Reference provider — einvoice_storecove. Storecove is a certified Peppol Access Point
with a REST API. The module submits the generated EN 16931 UBL/CII (base64, rawDocumentData)
to POST /document_submissions; Storecove parses it, converts to the recipient country’s
national format where required, and transmits — so one integration reaches the whole Peppol
network plus the national systems it covers. Configure it in the Integrations catalog with a
Storecove API key and the sending company’s LegalEntity id (both from the Storecove
dashboard; use a sandbox key to test). Inbound uses Storecove’s pull-mode webhook queue.
Reference provider — einvoice_sovos. Sovos is a global compliance network for the
clearance-model countries (Brazil, Saudi Arabia, Mexico, India) as well as Peppol. Unlike an
Access Point, Sovos does the country conversion, cryptographic signing, and government clearance
itself — you submit a Sovos Canonical Invoice (SCI), which is UBL 2.1 wrapped in a Standard
Business Document (SBD) envelope. The module therefore reuses the same generated UBL and wraps
it (the SBDH carries the country + business process Sovos routes on), submitting base64 to POST /v1/documents with OAuth (API key + secret). Configure it with the Sovos key/secret and a
sandbox toggle. Note: the plain EN 16931 UBL clears in UBL-accepting jurisdictions; the hardest
clearance countries (e.g. Brazil) require country-specific SCI content beyond the core UBL,
which is added per country on top of this provider.
National profiles
Section titled “National profiles”A profile selects the standard/national flavour of the generated document. The base
ships Peppol BIS Billing 3.0; a country module adds its own profile by extending
FinancialDocument — contributing the profile name to the einvoice_profile selection and
overriding two hooks (guarding on the profile value, delegating to super() for the rest):
class XRechnungDocument(Model): __inherit__ = "FinancialDocument" _selection_add = {"einvoice_profile": ["XRechnung 3.0"]}
async def _einvoice_customization_id(self): if self.einvoice_profile == "XRechnung 3.0": return "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_3.0" return await super()._einvoice_customization_id()
async def _einvoice_profile_validation(self): errors = await super()._einvoice_profile_validation() if self.einvoice_profile == "XRechnung 3.0": # ... append the national (BR-DE) rule violations ... return errors_einvoice_customization_id()sets the UBLcbc:CustomizationIDfor the profile._einvoice_profile_validation()returns the profile’s national rule violations, which are checked alongside the core EN 16931 set on validate/generate.
The user picks the profile per invoice (E-Invoicing tab). Two reference profiles ship:
-
l10n_de_einvoice— XRechnung 3.0. Same Peppol BIS UBL syntax, a German customization, and the BR-DE rules (Leitweg-ID buyer reference, seller contact point, IBAN payment means). It only overrides_einvoice_customization_id+_einvoice_profile_validation. -
l10n_fr_einvoice— Factur-X. France’s format is CII (UN/CEFACT Cross Industry Invoice), not UBL, and is delivered as a hybrid PDF (the CII embedded in the invoice PDF). It overrides_einvoice_renderto build CII instead of UBL, and adds a Download Factur-X PDF action that renders the invoice report and embeds the CII. Note: the module produces the CII + embeds it with the Factur-X XMP, but strict PDF/A-3 conformance must be validated with an external validator (veraPDF / FNFE-MPE) before production — it is not asserted in-process. -
l10n_sa_einvoice— ZATCA (Saudi Arabia). ZATCA is UBL 2.1, so it reusesbuild_ubland only injects the KSA content (Commercial Registration Number as a supplierPartyIdentification, and the invoice-type-code subtype in thenameattribute) via a third hook,_einvoice_augment_ubl(root)— which lets a profile mutate the built UBL in place (applies whether the UBL is stored, sent via an Access Point, or handed to Sovos). BR-SA rules check the 15-digit3…3VAT and the CRN. The cryptographic stamp, ICV/PIH hash chain, QR, and ZATCA clearance are all performed by the transmission provider (Sovos) — the profile never touches the cryptography.
The base emits seller contact and SEPA payment means (from the company’s iban/bic) whenever
present, so those national requirements are satisfiable without profile-specific builder code.
-
l10n_in_einvoice— India GST (IRP). Adds the India-mandatory content via_einvoice_augment_ubl— GSTIN as the GST tax scheme, per-line HSN/SAC codes (from a newhsn_codeon the product), and place of supply (the buyer’s state asCountrySubentityCode). BR-IN validation checks the 15-char GSTIN, HSN on every line, and the place of supply. The provider registers the invoice with the IRP and returns the IRN + signed QR, and derives the CGST/SGST/IGST split from the rate and place of supply. -
l10n_mx_einvoice— Mexico CFDI 4.0. UBL-based (like Saudi): injects per-line SAT product (ClaveProdServ) and unit (ClaveUnidad) codes and the paymentFormaPago(asPaymentMeansCode); RFC travels via the SBDH. The provider maps to CFDI, applies the PAC stamp (timbrado), obtains the SAT UUID and clears. So a national profile has three hooks to override:_einvoice_customization_id(the CustomizationID),_einvoice_render(a different syntax, e.g. CII), and_einvoice_augment_ubl(inject/adjust UBL elements). Clearance-model countries add their content on the same base and transmit through a provider that performs the signing and government clearance.