Automation MCP Server Features Blog Pricing Contact
Automation

E-Invoicing on SAP BTP: ZUGFeRD, XRechnung and Factur-X from Integration Suite

Your billing documents already live in S/4HANA; the mandates want them as structured e-invoices. This guide adds that capability with one HTTP call from SAP BTP: a Cloud Integration iFlow (or a CAP application) posting billing data to a REST API and receiving a validated ZUGFeRD PDF/A-3, XRechnung XML, or Factur-X hybrid back. Includes credential handling in Security Material, an S/4 field mapping, the incoming-invoice path, and an honest look at where this sits next to SAP Document and Reporting Compliance.

If German enterprise runs on anything, it runs on SAP, and the e-invoicing mandates have turned every SAP billing process into a compliance question. Since January 2025 no German business may refuse a structured e-invoice, issuance becomes mandatory from 2027, France switches on in weeks, and the documents these regimes want (ZUGFeRD hybrids, XRechnung XML, Factur-X) are not what classic output management produces. The billing data is all there, posted and correct in S/4HANA; the gap is the last step between a billing document and a mandate-grade file.

This guide closes that gap from SAP BTP with one HTTP call. Two implementation paths, same API underneath: a Cloud Integration iFlow for integration teams who live in Integration Suite, and a CAP application for development teams building on BTP directly. Either way, billing data goes out as JSON and a validated document comes back, with the compliance machinery (EN 16931 rules, KoSIT and FeRD artifacts, PDF/A-3 conformance) staying server-side where it updates itself.

And because every SAP reader will ask within the first paragraph: yes, SAP has its own answer here, and this post is honest about it before showing any code.


The SAP e-invoicing gap

Three facts collide in a typical SAP landscape:

The mandates are format-specific. German B2B runs on ZUGFeRD (PDF/A-3 with embedded CII XML, profiles EN 16931 and above), German B2G requires XRechnung (pure XML validated against the KoSIT rules, Leitweg-ID mandatory), and France's reform makes structured e-invoices compulsory from September 2026, delivered through certified platforms (Plateformes Agréées, the platforms formerly known as PDPs) that validate documents on acceptance.

Classic output produces the wrong artifact. The forms your output management renders are exactly what they were designed to be: documents for humans. The mandates want machine-readable structure alongside or instead of them, plus archival-grade containers, plus rule sets that change on regulators' calendars.

The data is already perfect. Unlike most platforms covered on this blog, an SAP billing document is a complete, tax-correct invoice model. Nothing needs enriching; it needs expressing in the right format, which makes this one of the cleanest integrations in the series: map, POST, attach.


Where this sits next to SAP DRC

SAP Document and Reporting Compliance is SAP's own suite for electronic documents and statutory reporting, and it does cover the German and French regimes alongside dozens of others. If your organization has licensed DRC, scoped it, and rolled it out for these countries, that is a strategic platform decision made at a level above any single integration.

The honest observation is about the shape of that decision: DRC adoption is a program. Licensing, country activation, eDocument configuration, testing cycles, and a timeline measured in project phases, which is proportionate when the goal is a global compliance platform, and disproportionate when the goal is "our German customers need ZUGFeRD next month and the French deadline is in weeks."

The REST API route is one iFlow. The document layer (generation, validation, extraction) runs as a service that is current with every FeRD, KoSIT, and FNFE-MPE release on its effective date, with nothing installed, activated, or transported in your landscape, no waiting on suite release cycles, and professional support behind the endpoint. It coexists cleanly with whatever your long-term platform strategy becomes, because an iFlow is the cheapest thing in SAP to retire; meanwhile the mandate is met. That is the complete-compliance-service trade: the moving target is our job, and your integration is finished the day it works.


The architecture

One sentence: billing data leaves S/4HANA (OData API, IDoc, or an event-triggered read), an iFlow or CAP service maps it to the invoice JSON and POSTs it to the create endpoint, and the validated document comes back as binary content to attach, archive, and dispatch through your existing channels.

CustomerFormatEndpointComes back as
German business (B2B)ZUGFeRD EN 16931/v1/create/zugferdHybrid PDF/A-3
German authority (B2G)XRechnung 3.0/v1/create/xrechnungXML + Leitweg-ID
French businessFactur-X EN 16931/v1/create/facturxHybrid PDF/A-3
Peppol recipientPeppol BIS 3.0/v1/create/ublUBL XML

Every row accepts the same JSON body, so format routing is a Router step keyed on the customer's country and sector flag, not four integrations. Totals and the VAT breakdown are computed and validated server-side from the line items, which removes an entire class of rounding reconciliation between SAP pricing and the e-invoice.


Path 1: a Cloud Integration iFlow

For teams in Integration Suite, the whole integration is one iFlow with standard steps:

1. Credentials in Security Material. Create a free InvoiceXML account (100 free credits with the 30-day trial, no credit card) and store the API key as a User Credentials artifact, for example named InvoiceXML_ApiKey, so it lives in the tenant's secure store rather than in the iFlow.

2. Set the headers in a short Groovy step. The API authenticates with a Bearer token, and the standard pattern reads the credential from the secure store at runtime:

import com.sap.gateway.ip.core.customdev.util.Message
import com.sap.it.api.ITApiFactory
import com.sap.it.api.securestore.SecureStoreService

def Message processData(Message message) {
    def secureStore = ITApiFactory.getService(SecureStoreService.class, null)
    def credential = secureStore.getUserCredential("InvoiceXML_ApiKey")

    message.setHeader("Authorization", "Bearer " + new String(credential.getPassword()))
    message.setHeader("Content-Type", "application/json")
    return message
}

3. Map the billing document to invoice JSON. A message mapping or Groovy step builds the body from the billing document payload; the field mapping below covers what goes where. The shape the endpoint expects:

{
  "invoice": {
    "invoiceNumber": "90001234",
    "issueDate": "2026-07-30",
    "currency": "EUR",
    "seller": {
      "name": "Rheinstahl Komponenten GmbH",
      "vatIdentifier": "DE812345670",
      "postalAddress": { "line1": "Industriepark 12", "city": "Duisburg", "postCode": "47059", "country": "DE" }
    },
    "buyer": {
      "name": "Bergland Maschinenbau AG",
      "postalAddress": { "line1": "Innsbrucker Ring 4", "city": "Rosenheim", "postCode": "83022", "country": "DE" }
    },
    "paymentDetails": { "paymentAccountIdentifier": "DE45500105175923118912" },
    "lines": [
      {
        "quantity": 250,
        "item": { "name": "Praezisionslager Serie K" },
        "priceDetails": { "netPrice": 34.80 },
        "vatInformation": { "rate": 19 }
      }
    ]
  }
}

4. POST via the HTTP receiver adapter. Address https://api.invoicexml.com/v1/create/zugferd, method POST. On HTTP 200 the message body is the finished document (binary PDF for the hybrid formats, XML for XRechnung). On HTTP 400 the body is a JSON problem document listing the violated EN 16931 rules as structured findings with field paths; route it to an exception subprocess and surface the findings, because they name exactly which field a billing clerk needs to fix, and retrying unchanged data reproduces them.

5. Deliver through what you already have. Attach the document to the billing document via your archiving setup, hand it to the mail adapter, or drop it wherever your dispatch expects output. The e-invoice rides your existing channels; only its production moved.

Mapping S/4 billing data to invoice JSON

Everything the API requires exists on the billing document and the business partner master; the standard billing document OData API (API_BILLING_DOCUMENT_SRV) exposes it all. The mapping worth pinning up:

SAP sourceJSON pathNote
Billing document numberinvoice.invoiceNumberBT-1
Billing dateinvoice.issueDateFormat yyyy-MM-dd
Transaction currencyinvoice.currencyISO code as-is
Company code data (name, VAT registration, address)invoice.sellerSeller VAT identifier is mandatory
Sold-to / payer business partner (name, address)invoice.buyerCountry as ISO code
House bank IBANinvoice.paymentDetails.paymentAccountIdentifierRecommended for B2B
Item descriptionlines[].item.namePer billing item
Billing quantity / net pricelines[].quantity, lines[].priceDetails.netPriceNet values; totals are computed by the API
Tax rate from the item's tax codelines[].vatInformation.ratePer-rate VAT breakdown computed server-side
Leitweg-ID from the business partner (B2G only)invoice.buyerReferenceCustomer master extension field; see the XRechnung section

Deliberately absent: document totals, tax totals, and the VAT breakdown. The API computes them from the lines and refuses to emit a document whose numbers do not reconcile, so a pricing-versus-rounding discrepancy becomes a structured 400 in your monitoring instead of a rejected invoice at your customer.


Path 2: a CAP application

Development teams building on BTP with the Cloud Application Programming model skip the iFlow entirely; Node 18+ ships fetch, so the integration is a service handler:

const cds = require("@sap/cds");

module.exports = cds.service.impl(function () {
  this.on("issueInvoice", async (req) => {
    const invoice = await buildInvoicePayload(req.data.billingDocument);

    const response = await fetch("https://api.invoicexml.com/v1/create/zugferd", {
      method: "POST",
      headers: {
        Authorization: `Bearer ${process.env.INVOICEXML_API_KEY}`,
        "Content-Type": "application/json"
      },
      body: JSON.stringify({ invoice })
    });

    if (!response.ok) {
      // 400 carries the violated EN 16931 rules as structured findings
      return req.error(422, await response.text());
    }
    return Buffer.from(await response.arrayBuffer());
  });
});

For production, hold the key in the BTP Destination service or a bound user-provided service instead of a raw environment variable; the call itself does not change. The full JavaScript treatment of both German formats, including the intake pipeline, lives in the companion guide to ZUGFeRD and XRechnung in Node.js.


Validate before dispatch

Documents generated by the create endpoints are validated against the full official rule sets before delivery, so the generation path needs no second check. Where a validation step earns its place in an SAP landscape is at the boundaries: documents produced by other systems in the group, files received from subsidiaries, or output from a legacy process you have not migrated yet. POST /v1/validate/zugferd and POST /v1/validate/xrechnung accept documents from any producer and return JSON findings with rule ids, plain-language messages, and field paths that map cleanly onto an exception workflow, and the online validator runs the identical check interactively when someone just needs a quick verdict.


Incoming supplier e-invoices

Reception has been mandatory for every German business since January 2025, and the supplier side of an SAP landscape feels it first: structured e-invoices arriving where PDFs used to. The same integration layer handles the direction reversal with two endpoints:

Structured documents: POST /v1/extract/json parses the embedded XML of a ZUGFeRD or Factur-X hybrid, or standalone XRechnung, CII, or UBL XML, deterministically into one normalized JSON shape. An iFlow maps that onto your supplier invoice interface or a staging table for clearing; what the supplier declared is exactly what gets proposed for posting.

Plain PDFs: for the suppliers who still send ordinary PDFs, POST /v1/parse/json reads the document with AI (scans included) and returns the same JSON shape plus a confidence object with overall and per-area scores, so your flow can auto-propose the certain reads and route the uncertain ones to a clearing workflow. Non-invoices are rejected with a structured error before they reach your posting logic, and POST /v1/extract/attachments unpacks embedded supporting documents (BG-24 delivery notes and timesheets, common on German B2G documents) as a ZIP.


XRechnung for German B2G

Invoicing a federal ministry, state agency, or municipality from SAP means XRechnung rather than ZUGFeRD: pure XML, validated by portals such as ZRE and OZG-RE against the KoSIT rules. The same iFlow covers it with the endpoint swap plus two data additions: the buyer's Leitweg-ID in invoice.buyerReference (assigned during onboarding, stored on the business partner, enforced by rule BR-DE-15) and the mandatory seller contact group with electronic addresses for both parties, all of which the company code and business partner data already hold. The response is XRechnung 3.0 XML validated against the current KoSIT rule set, and POST /v1/render/xrechnung/to/pdf produces a human-readable preview for approvals, since pure XML gives an accountant nothing to look at. The full B2G treatment, including the validation layers and error semantics, is in the XRechnung API toolkit.


Endpoint reference

OperationEndpointInputOutput
Create ZUGFeRDPOST /v1/create/zugferdJSONPDF/A-3 binary
Create XRechnungPOST /v1/create/xrechnungJSONXRechnung 3.0 XML
Create Factur-XPOST /v1/create/facturxJSONPDF/A-3 binary
Create Peppol UBLPOST /v1/create/ublJSONUBL XML
Validate ZUGFeRD / XRechnungPOST /v1/validate/zugferd, /v1/validate/xrechnungHybrid PDF / XMLValidation JSON
Extract as JSONPOST /v1/extract/jsonHybrid PDF or CII/UBL XMLStructured JSON
Parse PDF with AIPOST /v1/parse/jsonAny invoice PDF (typed, scanned)Structured JSON + confidence
Extract attachmentsPOST /v1/extract/attachmentsHybrid PDF or CII/UBL XMLZIP archive
Render XRechnung as PDFPOST /v1/render/xrechnung/to/pdfXRechnung XMLPDF binary

Full OpenAPI 3.1 schema: api.invoicexml.com/v1/openapi  |  Interactive API explorer: api.invoicexml.com/v1/scalar


Get started

The shortest path to a first document: create the account, store the key as a User Credentials artifact, and POST the sample body above from a test iFlow (or plain curl) to /v1/create/zugferd. What comes back is a finished, validated hybrid your archiving can hold and your customers' software can book.

Create a free InvoiceXML account → get 100 free credits with the 30-day trial, no credit card required.

Related resources:


InvoiceXML is a REST API for European e-invoice compliance covering ZUGFeRD, XRechnung, Factur-X, Peppol UBL, and CII. Stateless processing, GDPR compliant by architecture, and callable from any SAP-adjacent stack: Cloud Integration, CAP on BTP, or any middleware that speaks HTTPS.

Start free today

Ready to automate your invoices?

Validate, convert and embed compliant e-invoices through one API. Start your 30-day free trial. No credit card required.

GDPR Compliant No credit card required Setup in minutes
Peppol UBL
Factur-X
EN 16931
142 / 142 passed
Compliant
PDF/A-3 embedded