Skip to content

Germany — E-INVOICE DE (Unified API)

In Germany, fiskaly supports sending and receiving B2B e-invoices. E-invoicing is regulated by the Federal Ministry of Finance (BMF — Bundesministerium der Finanzen). All e-invoices are required to comply with EN 16931, which is satisfied by formats such as XRechnung, ZUGFeRD, or Peppol BIS 3.0 Billing. fiskaly does not archive German e-invoices — see Archiving.

fiskaly generates EN 16931-compliant e-invoices and delivers them over one of two channels, chosen per invoice on the recipient (recipients[].invoicing): by email — as ZUGFeRD or XRechnung — or over the PEPPOL network, as XRechnung.

The two directions are configured differently:

This page covers the Germany-specific requirements that complement the General Step-by-step Integration. Make sure you have the following taxpayer information ready before proceeding:

  • fiscalization.vat_id_number — VAT identification number (Umsatzsteuer-ID), 9 digits without the DE prefix
  • fiscalization.tax_id_number — personal tax identification number (Steuer-ID), 11 digits. Required for INDIVIDUAL Taxpayers.
  • name — registered legal name and trade name of the company or individual
  • address — registered legal address of the company or individual

Sending e-invoices: recipient requirements

Section titled “Sending e-invoices: recipient requirements”

To send an e-invoice, you specify its recipient and how the invoice should reach them — right on the invoice record. When you create the invoice (TRANSACTION::INVOICE) with createRecord, add the recipient to its recipients array.

As the General Step-by-step Integration explains, each recipient must be a BUSINESS with a populated invoicing block. Beyond the standard details every e-invoice requires (recipient name, address, tax identification, invoice lines, and so on), Germany adds the delivery channel on the recipient:

  • recipients[].type = BUSINESS
  • recipients[].identification.type = VAT — German e-invoicing identifies the buyer by VAT identification number
  • recipients[].address.country = DE — recipients must be in Germany
  • recipients[].invoicing.type = EMAIL or PEPPOL — the delivery channel
  • recipients[].invoicing.email — (EMAIL only) the recipient’s email address
  • recipients[].invoicing.format — (EMAIL only, optional) the document format
  • recipients[].invoicing.identifier — (PEPPOL only) the recipient’s PEPPOL Network Identifier, in the form <scheme code>:<value> — typically 9930:<VAT number> for a German business
invoicing.typeAlso requiredHow fiskaly delivers it
EMAILinvoicing.emailEmailed to that address, as ZUGFeRD or XRechnung depending on invoicing.format.
PEPPOLinvoicing.identifierSent to the recipient’s PEPPOL endpoint as XRechnung — see the XRechnung limitation.

You choose the channel per invoice, not once per recipient — the same business can receive one invoice by email and the next over PEPPOL.

Each entry in payments is either a payment already received (CASH, CARD, ONLINE, VOUCHER, OTHER) or the amount still open (OUTSTANDING). Received payments appear on the invoice as the prepaid amount, and the date of the OUTSTANDING entry becomes the invoice’s due date. For a fully paid invoice, omit OUTSTANDING.

Every payment needs type and details.amount. Some types need more:

typeAlso required
CASH—
CARDnumber (masked card number, for example ************1234) and kind
ONLINEname, for example the payment provider
VOUCHERnumber and kind
OTHER— (name is optional)
OUTSTANDINGconcept (GOOD, SERVICE or INVOICE) and details.date, the due date

concept is accepted only on OUTSTANDING. On any other payment type, the request is rejected with 400.

In Germany, registering on the PEPPOL network is optional — you opt in per System.

Declare it on the E_INVOICE_SERVICE System with createSystem:

{
"content": {
"type": "E_INVOICE_SERVICE",
"location": { "id": "..." },
"software": { "...": "..." },
"registrations": [{ "type": "PEPPOL" }]
}
}

Or add it to an existing System with updateSystem:

{
"content": {
"registrations": [{ "type": "PEPPOL" }]
}
}

What follows from that choice:

  • registrations omitted — the System sends by email only. No Proof of Ownership is involved and the System commissions straight to mode OPERATIVE.
  • registrations includes PEPPOL — a Proof of Ownership document is required. On commissioning, the System’s state becomes COMMISSIONED but its mode becomes DEGRADED, and the System carries a log entry recording that the Proof of Ownership is missing.

To move the System into OPERATIVE mode, upload the Proof of Ownership as described in Step 11 of the general integration guide. Verification takes up to 72 hours; once it completes, the System transitions automatically and the log entry is removed. See the Proof of Ownership section for what the document must show.

On the recipient in your createRecord request, set:

  • recipients[].invoicing.type = PEPPOL
  • recipients[].invoicing.identifier — the recipient’s PEPPOL Network Identifier

Two things are required before this works: your E_INVOICE_SERVICE System must be registered on the PEPPOL network (see Registering for PEPPOL), and you need the recipient’s PEPPOL Network Identifier. fiskaly takes care of the identifier scheme.

Invoices sent this way are generated as XRechnung. recipients[].invoicing.format plays no part here — the format is not selectable on this channel.

Sending by email: choosing the document format

Section titled “Sending by email: choosing the document format”

When the channel is EMAIL, you decide which document format fiskaly generates. Set it on the same recipient in your createRecord request, via recipients[].invoicing.format:

ValueFormat
ZUGFERD_V2 (default)ZUGFeRD — a hybrid document: a human-readable PDF/A-3 with the structured XML embedded inside it.
XRECHNUNG_V3XRechnung — a pure structured XML invoice, with no PDF layer.

The field is optional: omit it and fiskaly generates ZUGFERD_V2. Both formats comply with EN 16931.

fiskaly sends the email on behalf of the seller, from no-reply.e-invoicing@fiskaly.com. The subject is “Your Invoice” and the text is in English. The email names the seller and refers the recipient to the seller for questions about the invoice.

The email is sent right after the invoice is created (processing is asynchronous, see below). There is no separate send trigger: to delay the email, delay the createRecord call.

The invoice is attached as invoice_<id>.xml for XRechnung or invoice_<id>.pdf for ZUGFeRD, where <id> is the ID of the E_INVOICE::TRANSMISSION Record.

Every invoice sent over PEPPOL is generated as XRechnung, and so is every email invoice with XRECHNUNG_V3. XRechnung requires two fields that ZUGFeRD does not:

FieldXRechnung ruleValue
document.references.buyerBR-DE-151–32 characters: letters, digits, spaces and . - _ /. Required on every invoice, not only for public-sector buyers.
seller.phoneBR-DE-6The seller’s contact phone number in E.164 format, for example +49301234567.

Each invoice takes two createRecord calls, as described in Step 12 of the general integration guide: an INTENTION, then a TRANSACTION::INVOICE that references it. Send each call with a new idempotency key. Replace the IDs and values with your own.

Intention
{
"content": {
"type": "INTENTION",
"system": {
"id": "<E_INVOICE_SERVICE System ID>"
},
"operation": {
"type": "TRANSACTION"
}
}
}
Invoice by email as ZUGFeRD
{
"content": {
"type": "TRANSACTION",
"record": {
"id": "<INTENTION Record ID>"
},
"operation": {
"type": "INVOICE",
"document": {
"number": "RE-2026-0001",
"issued_at": "2026-10-05T10:00:00+02:00"
},
"entries": [
{
"type": "SALE",
"data": {
"type": "ITEM",
"text": "Consulting service",
"unit": {
"quantity": "2",
"price": {
"exclusive": "100.00",
"inclusive": "119.00"
}
},
"value": {
"base": "200.00"
},
"vat": {
"type": "VAT_RATE",
"code": "STANDARD",
"percentage": "19.00",
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
},
"details": {
"concept": "SERVICE"
}
}
],
"recipients": [
{
"type": "BUSINESS",
"name": "Beispiel GmbH",
"address": {
"line": {
"type": "STREET_NUMBER",
"street": "Alexanderplatz",
"number": "1"
},
"code": "10178",
"city": "Berlin",
"country": "DE"
},
"identification": {
"type": "VAT",
"number": "369204173"
},
"invoicing": {
"type": "EMAIL",
"email": "invoices@beispiel-gmbh.de",
"format": "ZUGFERD_V2"
}
}
],
"payments": [
{
"type": "OUTSTANDING",
"details": {
"amount": "238.00",
"currency": "EUR",
"date": "2026-11-04"
},
"concept": "SERVICE"
}
],
"breakdown": [
{
"type": "VAT_RATE",
"code": "STANDARD",
"percentage": "19.00",
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
],
"totals": {
"vat": {
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
}
}
}
}
Invoice by email as XRechnung
{
"content": {
"type": "TRANSACTION",
"record": {
"id": "<INTENTION Record ID>"
},
"operation": {
"type": "INVOICE",
"document": {
"number": "RE-2026-0001",
"issued_at": "2026-10-05T10:00:00+02:00",
"references": {
"buyer": "PO-4711"
}
},
"seller": {
"name": "Max Mustermann",
"phone": "+49301234567",
"email": "billing@example-seller.de"
},
"entries": [
{
"type": "SALE",
"data": {
"type": "ITEM",
"text": "Consulting service",
"unit": {
"quantity": "2",
"price": {
"exclusive": "100.00",
"inclusive": "119.00"
}
},
"value": {
"base": "200.00"
},
"vat": {
"type": "VAT_RATE",
"code": "STANDARD",
"percentage": "19.00",
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
},
"details": {
"concept": "SERVICE"
}
}
],
"recipients": [
{
"type": "BUSINESS",
"name": "Beispiel GmbH",
"address": {
"line": {
"type": "STREET_NUMBER",
"street": "Alexanderplatz",
"number": "1"
},
"code": "10178",
"city": "Berlin",
"country": "DE"
},
"identification": {
"type": "VAT",
"number": "369204173"
},
"invoicing": {
"type": "EMAIL",
"email": "invoices@beispiel-gmbh.de",
"format": "XRECHNUNG_V3"
}
}
],
"payments": [
{
"type": "OUTSTANDING",
"details": {
"amount": "238.00",
"currency": "EUR",
"date": "2026-11-04"
},
"concept": "SERVICE"
}
],
"breakdown": [
{
"type": "VAT_RATE",
"code": "STANDARD",
"percentage": "19.00",
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
],
"totals": {
"vat": {
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
}
}
}
}
Invoice over PEPPOL (XRechnung)
{
"content": {
"type": "TRANSACTION",
"record": {
"id": "<INTENTION Record ID>"
},
"operation": {
"type": "INVOICE",
"document": {
"number": "RE-2026-0001",
"issued_at": "2026-10-05T10:00:00+02:00",
"references": {
"buyer": "PO-4711"
}
},
"seller": {
"name": "Max Mustermann",
"phone": "+49301234567",
"email": "billing@example-seller.de"
},
"entries": [
{
"type": "SALE",
"data": {
"type": "ITEM",
"text": "Consulting service",
"unit": {
"quantity": "2",
"price": {
"exclusive": "100.00",
"inclusive": "119.00"
}
},
"value": {
"base": "200.00"
},
"vat": {
"type": "VAT_RATE",
"code": "STANDARD",
"percentage": "19.00",
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
},
"details": {
"concept": "SERVICE"
}
}
],
"recipients": [
{
"type": "BUSINESS",
"name": "Beispiel GmbH",
"address": {
"line": {
"type": "STREET_NUMBER",
"street": "Alexanderplatz",
"number": "1"
},
"code": "10178",
"city": "Berlin",
"country": "DE"
},
"identification": {
"type": "VAT",
"number": "369204173"
},
"invoicing": {
"type": "PEPPOL",
"identifier": "9930:DE369204173"
}
}
],
"payments": [
{
"type": "OUTSTANDING",
"details": {
"amount": "238.00",
"currency": "EUR",
"date": "2026-11-04"
},
"concept": "SERVICE"
}
],
"breakdown": [
{
"type": "VAT_RATE",
"code": "STANDARD",
"percentage": "19.00",
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
],
"totals": {
"vat": {
"amount": "38.00",
"exclusive": "200.00",
"inclusive": "238.00"
}
}
}
}
}

Sending is asynchronous. createRecord returns once the TRANSACTION::INVOICE is accepted, and the invoice and its transmission are processed afterwards. There are no webhooks for this, so poll with retrieveRecord. Each Record shows its progress in mode: PROCESSING while work is ongoing, FINISHED once it is done. state then holds the outcome.

Once the TRANSACTION::INVOICE is FINISHED, COMPLETED alone does not mean the invoice was sent. Check that its logs contain no entry with "severity": "ERROR" and that used_in is present.

used_in.id is the E_INVOICE::TRANSMISSION Record. Poll it until its mode is FINISHED. Its state shows the outcome:

  • COMPLETED — the invoice was handed over for delivery.
  • FAILED — the invoice was not delivered. The reason is in the Record’s logs.

For email, COMPLETED means the invoice was handed over to fiskaly’s email gateway. Delivery to the recipient’s inbox cannot be confirmed, and bounces after that point are not reported on the Record.

If the email gateway rejects an email permanently, the transmission ends FAILED straight away. Temporary errors are retried in the background, so the transmission can stay in PROCESSING for a while. It ends FAILED only once all retries are used up.

A failed invoice was not issued. Send it again as a new TRANSACTION::INVOICE (new intention, new idempotency key) with the same invoice number — not as a CORRECTION. To correct an invoice that reached the buyer, issue a credit note.

For full details, see How to detect and handle failed invoices.

What you seeCause
ERROR log either party.telephones or party.people[0].telephones is required (BR-DE-6), nothing sentXRechnung invoice without seller.phone
ERROR log on the TRANSACTION::INVOICE, no used_in, nothing sentXRechnung invoice without document.references.buyer
400 on createRecordEmpty document.references.buyer, or another schema error
receiver does not support document typePEPPOL recipient not registered for XRechnung — see Sending via PEPPOL
422 Unprocessable Content when commissioningTaxpayer without vat_id_number

Call retrieveRecord on the E_INVOICE::TRANSMISSION (used_in.id) with compliance-artifact to get the generated e-invoice. The response is a JSON envelope. For XRechnung, content.compliance.artifact is:

{ "type": "application/xml", "data": "<base64>" }

For ZUGFeRD, content.compliance.artifact is the PDF/A-3 with the XML embedded:

{ "type": "application/pdf", "data": "<base64>" }

The Credit Note guide explains when and how to issue a credit note. This section covers only what is specific to Germany.

A credit note is a complete document of its own and doesn’t take over any data from the original invoice. Send the same recipient, channel and format as on the invoice. For XRechnung, also send seller.phone, seller.email and document.references.buyer again. Without them, nothing is sent and the record gets an ERROR log (BR-DE-6, BR-DE-7, BR-DE-15).

Payments on credit notes and reversing invoices

Section titled “Payments on credit notes and reversing invoices”

On a credit note, and on an invoice that reverses a credit note, payments describes what is still open on that document:

  • Settled part: type: OTHER with details.amount and details.currency, without a date.
  • Amount still to be paid: type: OUTSTANDING with concept, details.amount, details.currency and details.date, the due date (required).

The e-invoice shows the settled part as prepaid and the rest as payable by the due date. Both types can be combined on credit notes and on invoices.

DocumentSituationpayments
Credit noteRefund already paid to the customerOTHER = credited amount
Credit noteRefund still to be paidOUTSTANDING with due date
Credit notePart refundedOTHER (refunded part) + OUTSTANDING (rest)
Reversing invoiceRefund was fully paid out, customer pays it backOUTSTANDING = full amount
Reversing invoicePart of the refund paid out (e.g. 50.00 of 119.00)OTHER 69.00 + OUTSTANDING 50.00
Reversing invoiceNothing paid out, documents cancel outOTHER = full amount
Example — reversing invoice, part of the refund paid out
"payments": [
{
"type": "OTHER",
"details": {
"amount": "69.00",
"currency": "EUR"
}
},
{
"type": "OUTSTANDING",
"concept": "SERVICE",
"details": {
"amount": "50.00",
"currency": "EUR",
"date": "2026-11-30"
}
}
]

Receiving inbound e-invoices happens over PEPPOL, so it depends on the same PEPPOL registration that sending over PEPPOL does — including a verified Proof of Ownership. A Taxpayer that sends by email only cannot receive.

When you register a German Taxpayer on PEPPOL, fiskaly registers it for both sending and receiving by default. Inbound invoices addressed to the System’s PEPPOL identifier are matched to that System, and fiskaly creates a record of type E_INVOICE::RECEPTION for each one.

Call retrieveSystem to read compliance.state:

  • TRANSMISSION_RECEPTION — the System can send and receive.
  • TRANSMISSION_ONLY — the System can send only.

Every invoice addressed to your Taxpayer is received and stored automatically as a Record — there is no webhook, so you poll for new ones:

  1. Call listRecords and filter for E_INVOICE::RECEPTION.
  2. For each new Record, call retrieveRecord with compliance-artifact to get the signed XML.

listRecords returns the most recent Records (limit defaults to 10, newest first), so track what you have already processed.

You can retrieve the generated e-invoice of a sent invoice and the XML of a received invoice.