German B2B e-invoicing¶
This guide defines how Accountify and each client Odoo 19 Online database handle German domestic B2B electronic invoices. The client Odoo database remains the accounting system of record and the electronic-invoicing endpoint. Accountify provides tenant readiness, work routing, status monitoring, evidence, and exception handling; it does not become a parallel invoice issuer or archive.
Implementation contract, not legal advice
The rules below reflect official German guidance checked on July 3, 2026. Tax/legal owners must approve each tenant's applicability, exceptions, retention policy, and rollout. Regulatory changes must trigger a contract and capability review.
Regulatory baseline¶
Under section 14 UStG, an E-Rechnung is issued, transmitted, and received in a structured electronic format that enables electronic processing. A standalone PDF is an other invoice, not an E-Rechnung, for supplies performed from January 1, 2025 onward.
The BMF E-Rechnung FAQ establishes the current operational baseline:
| Date or period | Requirement |
|---|---|
| From January 1, 2025 | Domestic businesses must be able to receive E-Rechnungen. An email inbox is legally sufficient, although Accountify uses structured intake where enabled. |
| January 1, 2025 through December 31, 2026 | All issuers may use paper or, with recipient consent, another electronic format such as PDF instead of an E-Rechnung. |
| Through December 31, 2027 | The preceding issue transition continues for issuers whose prior-year turnover does not exceed EUR 800,000. Non-conforming legacy EDI may also continue through this date. |
| After the applicable transition | A qualifying domestic B2B invoice must be issued as an E-Rechnung unless an exception applies. |
The BMF identifies XRechnung and ZUGFeRD from version 2.0.1, excluding the MINIMUM and BASIC-WL profiles, as common compliant formats. All VAT invoice-required information must be present in the structured part. For a hybrid document, the structured data is authoritative if it differs from the rendered image.
Common exclusions include B2C invoices, many VAT-exempt supplies, invoices up to EUR 250 gross, travel tickets that qualify as invoices, and supplies by small businesses under the applicable Kleinunternehmer rule. B2G requirements are separate and can impose different formats, identifiers, thresholds, and transport routes. Applicability must therefore be decided from transaction facts, not merely the customer's country.
Product boundary¶
| Concern | Authority and responsibility |
|---|---|
| Legal invoice and ledger record | Client Odoo |
| Structured XML and Odoo attachments | Client Odoo; Accountify may retain encrypted evidence under the approved retention policy |
| E-invoice format and customer endpoint | Client Odoo partner/company configuration |
| Peppol registration and transport | Client Odoo/Odoo Peppol service, per company and endpoint |
| Work queue, review, readiness, exception, and status projection | Accountify |
| Tax applicability and exception policy | Approved tenant accounting policy |
| Cross-client reporting | Accountify projections and warehouse marts; never a second ledger |
Peppol is a transport network, not the German mandate itself. German law does not prescribe one transport path. Accountify supports Odoo's Peppol path first because it provides structured send/receive behavior and status evidence, while retaining an email/upload path for valid structured files and counterparties not using Peppol.
Verified Odoo 19 surface¶
The current runtime snapshot confirms account_peppol, account_edi_ubl_cii, documents_account_peppol, and German localization support. Odoo's electronic invoicing documentation states that Odoo can generate structured invoice XML, send invoices through Peppol, and receive Peppol vendor bills either as draft bills in a purchase journal or as Documents records.
| Purpose | Model and verified fields | Accountify policy |
|---|---|---|
| Company registration | res.company: account_peppol_proxy_state, peppol_can_send, peppol_eas, peppol_endpoint |
Read for readiness; configuration remains an authorized Odoo administration action |
| Inbound routing | res.company: peppol_reception_mode, peppol_purchase_journal_id, documents_account_peppol_folder_id |
Read and validate against approved tenant profile |
| Partner format and route | res.partner: invoice_edi_format, invoice_sending_method, peppol_eas, peppol_endpoint, peppol_verification_state |
Read; controlled configuration only after counterparty verification |
| Invoice document | account.move: ubl_cii_xml_id, ubl_cii_xml_filename, peppol_message_uuid, peppol_move_state, state, type, totals, and write_date |
Read and synchronize; draft/post behavior follows the AP or AR contract |
| Purchase journal | account.journal: is_peppol_journal, incoming_einvoice_notification_email |
Read readiness and routing |
| Odoo proxy registration | account_edi_proxy_client.user: edi_identification, edi_mode, proxy state |
Operations-only read; secrets and private keys are prohibited from Accountify projections |
The runtime exposes partner formats zugferd, xrechnung, and ubl_bis3; Peppol delivery states ready, to_send, processing, done, error, and skipped; and company registration states from not_registered through receiver or rejected. These values are snapshot-specific and must be checked per tenant before enablement.
Do not build ordinary integration behavior on transient send wizards. An automated outbound send command requires a clone-proven, allowlisted Odoo business operation with fixed inputs and authoritative status readback. Until that proof exists, staff posts and sends in Odoo while Accountify monitors the result.
Tenant capability profile¶
Store one versioned profile per Odoo connection and company:
{
"contract_version": "einvoicing-capability.v1",
"company_id": 11,
"german_b2b_receive_supported": true,
"german_b2b_issue_supported": false,
"account_peppol_installed": true,
"ubl_cii_installed": true,
"german_localization_installed": true,
"peppol_proxy_state": "receiver",
"peppol_endpoint_scheme": "9930",
"peppol_endpoint_hash": "sha256:...",
"reception_mode": "journal",
"purchase_journal_id": 12,
"supported_formats": ["xrechnung", "zugferd", "ubl_bis3"],
"inbound_fixture_passed_at": "2026-07-03T10:00:00Z",
"outbound_fixture_passed_at": null,
"evidence_expires_at": "2026-08-02T10:00:00Z"
}
receive_supported and issue_supported are separate gates. Installation alone proves neither. A profile is enabled only when:
- the company, German localization, VAT identity, endpoint scheme/ID, and production/test mode are correct;
- Peppol registration is in the required send/receive state when Peppol is used;
- the purchase journal or Documents folder is configured and company-safe;
- the integration user can read required invoice, attachment, partner, journal, and status fields;
- valid and invalid XRechnung/ZUGFeRD fixtures produce the expected result;
- duplicate, credit-note, correction, attachment, and status-error cases pass;
- original structured content and required evidence remain retrievable under the approved retention policy; and
- capability evidence is current and drift monitoring is active.
One Peppol endpoint can have only one active receiver registration. Database migration, clone testing, or provider changes must not register a production endpoint in two places. Test with Odoo demo mode or an approved non-production endpoint.
Inbound supplier invoice flow¶
- Odoo receives the structured invoice through Peppol or an approved structured-file channel.
- Odoo creates a draft vendor bill in the configured purchase journal, or stores the document in the configured Documents folder for controlled conversion.
- Accountify synchronizes the bill, structured attachment identity/hash, vendor reference, totals, dates, status, and source metadata.
- The structured XML is the primary extraction source. OCR/vision is used only for an unstructured attachment or a supported enrichment need; it must not overwrite structured values silently.
- Accountify deduplicates and routes the item into the supplier invoice workbench, preserving the structured source and any human-readable representation.
- Staff resolves vendor, tax, account, analytic, PO/receipt, duplicate, and policy exceptions.
- Posting follows the AP review, authorization, freshness, and Odoo readback contract.
Inbound receipt does not prove tax correctness, entitlement to input VAT, successful posting, or payment approval. Invalid XML, unsupported profiles, supplier identity conflicts, and structured/rendered differences become explicit exceptions.
Outbound customer invoice flow¶
- The client invoice is created and posted in Odoo under the applicable AR workflow.
- Odoo selects the configured partner format and route. Customer endpoint details must be verified; prefilled values are not sufficient evidence.
- Odoo generates the structured document and sends it through the approved path. For Peppol, Odoo reports
doneafter delivery to the recipient's access point. - Accountify reads back invoice state, XML attachment, message UUID, Peppol state, customer endpoint hash, and source
write_date. - Accountify records delivered only when the configured success evidence is present.
queued,processing, timeout, missing XML, or divergent format becomes pending/exception, not success. - Corrections and credit notes use native Odoo document types and retain an explicit link to the original invoice. Accountify never edits a delivered structured artifact in place.
An access-point done state is transport evidence, not proof that the recipient accepted the commercial or tax treatment. Any later rejection/dispute remains a separate workflow.
Accountify API and projection contract¶
GET /api/v1/tenants/{tenant_id}/e-invoicing/capabilities
GET /api/v1/tenants/{tenant_id}/e-invoicing/documents
GET /api/v1/tenants/{tenant_id}/e-invoicing/documents/{document_id}
POST /api/v1/operations/tenants/{tenant_id}/e-invoicing/capability-scans
POST /api/v1/operations/tenants/{tenant_id}/e-invoicing/documents/{document_id}/refresh
The first implementation exposes status and operations controls; it does not expose arbitrary send/retry. A later outbound command requires its own OpenAPI operation, authorization, idempotency, clone proof, and readback acceptance.
Each einvoice_document_summary contains:
- tenant, connection, company, Odoo move ID, move type, state,
write_date, and local resource version; - direction, structured format, transport, source/destination endpoint hash, and message UUID where available;
- structured attachment ID, filename, SHA-256, immutable object-storage evidence reference when policy permits, and parse/validation result;
- invoice number/reference, issue date, partner ID, currency, untaxed/tax/total amounts as decimal strings;
- transport state, observed timestamps, last successful sync, exception code, and AP/AR work-item link; and
- no private key, API token, raw endpoint credential, or unrestricted attachment URL.
Projection rows are rebuildable. Odoo and the original structured artifact remain authoritative. A document key is scoped by (tenant_id, connection_id, company_id, odoo_move_id); message UUID, supplier reference, or attachment hash alone is not globally unique.
Deduplication and evidence¶
Inbound duplicate detection combines, where available:
- tenant/company and supplier identity;
- structured invoice ID and type;
- issue date and currency/amount;
- Peppol message UUID;
- original structured attachment SHA-256; and
- existing Odoo duplicate indicators and vendor bill reference.
Hash equality is strong duplicate evidence but not the only rule. A corrected invoice may reuse commercial references with different structured content; conversely, equivalent XML can serialize differently. Suspected duplicates are quarantined for review and are never silently discarded.
At minimum retain the original structured part unaltered, its hash, receipt/send timestamps, route/status evidence, Odoo record identity, and correction relationships. The BMF FAQ currently states an eight-year VAT retention period and requires the structured part to remain intact in its original form. The approved retention policy must also account for GoBD, commercial-law, litigation-hold, privacy, and client-contract requirements.
Failure and status policy¶
| Condition | Classification | Required action |
|---|---|---|
| Company not registered to receive | capability_blocked |
Correct Odoo registration; do not claim tenant readiness |
| Counterparty not found or cannot receive selected format | recipient_invalid |
Verify endpoint and agree another lawful route/format |
Odoo state ready, to_send, or processing |
pending |
Poll with bounded backoff; show age and next check |
Odoo state error |
delivery_failed |
Preserve safe error, open work item, correct, and use approved retry |
| Timeout during a future automated send | unknown |
Read invoice/message state before any redelivery |
| Missing or changed structured attachment | evidence_invalid |
Block completion and investigate drift |
| XML validation or business-rule failure | document_invalid |
Quarantine; do not downgrade silently to PDF |
| Structured data differs from rendered representation | content_mismatch |
Treat structured data as authoritative and require review |
Acceptance and rollout¶
Before enabling a company in production, run and retain evidence for:
- A valid inbound XRechnung and ZUGFeRD fixture, including structured-field extraction and original-file retrieval.
- An invalid XML/profile and missing-required-field fixture that is quarantined.
- Duplicate delivery and corrected invoice/credit-note cases.
- A valid outbound invoice to a controlled recipient, including generated XML, transport status, and recipient endpoint verification.
- Wrong endpoint, unsupported format, access-point error, delayed processing, and timeout/readback cases.
- Multi-company isolation, role restrictions, attachment authorization, redaction, and cross-tenant negative tests.
- Database clone/provider migration without accidental production Peppol registration.
- Retention retrieval and integrity verification from the authoritative store and any approved evidence copy.
Roll out through non-production fixture tests, one controlled company with manual send/review, a monitored cohort, and only then broader tenant enablement. Automate ordinary routing only after measured evidence shows no unexplained loss, duplicate posting, or status misclassification.