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:
Sending — B2B
Two delivery channels, chosen per invoice on the recipient: by email as ZUGFeRD or XRechnung, or over the PEPPOL network as XRechnung. Email needs no network registration.
Receiving — B2B
Over PEPPOL only, so it requires the optional PEPPOL registration and a verified Proof of Ownership. A Taxpayer that sends by email only cannot receive. Inbound XRechnung is not currently received.
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 theDEprefixfiscalization.tax_id_number— personal tax identification number (Steuer-ID), 11 digits. Required forINDIVIDUALTaxpayers.name— registered legal name and trade name of the company or individualaddress— registered legal address of the company or individual
A German E_INVOICE_SERVICE System cannot be commissioned unless the
Taxpayer’s fiscalization carries a valid vat_id_number. The Steuer-ID in
tax_id_number does not satisfy this — German e-invoices require a
VAT-shaped tax identity, so the two fields are not interchangeable here.
Commissioning without it fails with 422 Unprocessable Content.
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=BUSINESSrecipients[].identification.type=VAT— German e-invoicing identifies the buyer by VAT identification numberrecipients[].address.country=DE— recipients must be in Germanyrecipients[].invoicing.type=EMAILorPEPPOL— the delivery channelrecipients[].invoicing.email— (EMAIL only) the recipient’s email addressrecipients[].invoicing.format— (EMAIL only, optional) the document formatrecipients[].invoicing.identifier— (PEPPOL only) the recipient’s PEPPOL Network Identifier, in the form<scheme code>:<value>— typically9930:<VAT number>for a German business
invoicing.type | Also required | How fiskaly delivers it |
|---|---|---|
EMAIL | invoicing.email | Emailed to that address, as ZUGFeRD or XRechnung depending on invoicing.format. |
PEPPOL | invoicing.identifier | Sent 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.
Without the invoicing block, the e-invoice is created but not delivered to
the recipient.
Payments on the invoice
Section titled “Payments on the invoice”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:
type | Also required |
|---|---|
CASH | — |
CARD | number (masked card number, for example ************1234) and kind |
ONLINE | name, for example the payment provider |
VOUCHER | number and kind |
OTHER | — (name is optional) |
OUTSTANDING | concept (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.
If payments contains more than one OUTSTANDING entry, only the first one
is used. The others are ignored without an error, so instalments with several
due dates can’t be represented.
Registering for PEPPOL
Section titled “Registering for PEPPOL”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:
registrationsomitted — the System sends by email only. No Proof of Ownership is involved and the System commissions straight to modeOPERATIVE.registrationsincludesPEPPOL— a Proof of Ownership document is required. On commissioning, the System’sstatebecomesCOMMISSIONEDbut itsmodebecomesDEGRADED, 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.
You can add PEPPOL to a System that is already commissioned. Doing so
re-runs the Proof of Ownership check, so a System that has never supplied the
document returns to mode DEGRADED until it does.
Sending via PEPPOL
Section titled “Sending via PEPPOL”On the recipient in your createRecord request, set:
recipients[].invoicing.type=PEPPOLrecipients[].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.
PEPPOL registers each participant for the specific document types it is able
to receive, and XRechnung is its own document type on the network. Sending to a
recipient that is not registered for XRechnung fails with
receiver does not support document type.
Conformance is not what decides this — XRechnung follows the Peppol BIS 3.0
rules, but that does not make it deliverable to a participant registered only
for Peppol BIS Billing 3.0. fiskaly does not currently generate Peppol BIS
Billing 3.0 for Germany: recipients[].invoicing.format offers ZUGFERD_V2
and XRECHNUNG_V3, and applies to the email channel only.
Until you know a recipient is registered for XRechnung, send to that recipient by email.
Sending to German public-sector buyers (B2G) is not supported yet, so Leitweg-ID addressing is not available.
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:
| Value | Format |
|---|---|
ZUGFERD_V2 (default) | ZUGFeRD — a hybrid document: a human-readable PDF/A-3 with the structured XML embedded inside it. |
XRECHNUNG_V3 | XRechnung — 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.
What the recipient receives
Section titled “What the recipient receives”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.
In the TEST environment, invoices sent by email are really delivered to the
address in recipients[].invoicing.email. Use addresses you control.
XRechnung requirements
Section titled “XRechnung requirements”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:
| Field | XRechnung rule | Value |
|---|---|---|
document.references.buyer | BR-DE-15 | 1–32 characters: letters, digits, spaces and . - _ /. Required on every invoice, not only for public-sector buyers. |
seller.phone | BR-DE-6 | The seller’s contact phone number in E.164 format, for example +49301234567. |
If either field is missing, the request still returns 200 and the
TRANSACTION::INVOICE ends COMPLETED, but it carries an ERROR log and no
transmission is created — nothing is sent. An empty buyer reference is
rejected with 400.
Example requests
Section titled “Example requests”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" } } } }}Checking whether an invoice was sent
Section titled “Checking whether an invoice was sent”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’slogs.
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.
Common errors
Section titled “Common errors”| What you see | Cause |
|---|---|
ERROR log either party.telephones or party.people[0].telephones is required (BR-DE-6), nothing sent | XRechnung invoice without seller.phone |
ERROR log on the TRANSACTION::INVOICE, no used_in, nothing sent | XRechnung invoice without document.references.buyer |
400 on createRecord | Empty document.references.buyer, or another schema error |
receiver does not support document type | PEPPOL recipient not registered for XRechnung — see Sending via PEPPOL |
422 Unprocessable Content when commissioning | Taxpayer without vat_id_number |
Retrieving a sent invoice
Section titled “Retrieving a sent invoice”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>" }Credit notes
Section titled “Credit notes”The Credit Note guide explains when and how to issue a credit note. This section covers only what is specific to Germany.
Data is not copied from the invoice
Section titled “Data is not copied from the invoice”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: OTHERwithdetails.amountanddetails.currency, without a date. - Amount still to be paid:
type: OUTSTANDINGwithconcept,details.amount,details.currencyanddetails.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.
| Document | Situation | payments |
|---|---|---|
| Credit note | Refund already paid to the customer | OTHER = credited amount |
| Credit note | Refund still to be paid | OUTSTANDING with due date |
| Credit note | Part refunded | OTHER (refunded part) + OUTSTANDING (rest) |
| Reversing invoice | Refund was fully paid out, customer pays it back | OUTSTANDING = full amount |
| Reversing invoice | Part of the refund paid out (e.g. 50.00 of 119.00) | OTHER 69.00 + OUTSTANDING 50.00 |
| Reversing invoice | Nothing paid out, documents cancel out | OTHER = 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 e-invoices
Section titled “Receiving e-invoices”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.
The receiving registration covers Peppol BIS Billing 3.0, not XRechnung. An
invoice addressed to your Taxpayer as XRechnung is rejected by the network
before it reaches fiskaly, so no E_INVOICE::RECEPTION Record is created for
it. This is the same document-type registration limit described under
Sending via PEPPOL.
Call retrieveSystem
to read compliance.state:
TRANSMISSION_RECEPTION— the System can send and receive.TRANSMISSION_ONLY— the System can send only.
Send-and-receive is the default, but fiskaly falls back to a send-only registration if the PEPPOL registration reports a conflict — typically because the Taxpayer’s PEPPOL participant identifier is already registered through another provider. The System stays usable for sending. If you expected to receive, contact the fiskaly support team at dev-support@fiskaly.com with the Taxpayer’s VAT ID.
Retrieving received invoices
Section titled “Retrieving received invoices”Every invoice addressed to your Taxpayer is received and stored automatically as a Record — there is no webhook, so you poll for new ones:
- Call
listRecordsand filter forE_INVOICE::RECEPTION. - For each new Record, call
retrieveRecordwithcompliance-artifactto get the signed XML.
listRecords returns the most recent Records (limit defaults to 10, newest
first), so track what you have already processed.
Archiving
Section titled “Archiving”German law requires e-invoices to be kept for 8 years in their original electronic format (§14b UStG). This applies to invoices you send and to invoices you receive. fiskaly does not archive e-invoices for Germany, so archiving stays with the Taxpayer.
You can retrieve the generated e-invoice of a sent invoice and the XML of a received invoice.