Zum Inhalt springen
FrankKi
iOS Download

E-invoicing: ZUGFeRD and XRechnung

A sent invoice yields two artifacts besides the paper letter: a ZUGFeRD PDF/A-3 with EN 16931 XML embedded, and a standalone XRechnung XML. Both are built from the same validated payload the letter was printed from, and both are download-only, so you can email them and archive them yourself. FrankKi never transmits an e-invoice to Peppol or to a Leitweg-ID.

  1. 1

    What FrankKi does and does not do

    FrankKi turns one invoice into two things: the printed letter that gets delivered by post, and the electronic invoice for download. The e-invoice comes in two formats, ZUGFeRD (a PDF/A-3 with EN 16931 XML embedded) and XRechnung (plain XML). Both are explicitly download-only: FrankKi does not transmit any e-invoice to a portal, there is no Peppol delivery and no delivery to a Leitweg-ID. If your recipient requires a portal, you download the file and submit it there yourself.

  2. 2

    Three calls, one document

    The e-invoice is not a tool of its own, it falls out of the normal flow. document_create takes the structured payload (line items, VAT rates, payment terms), re-computes everything and stores the letter as a draft. order_send sends exactly that letter using the letterId from step 1. After that, document_get returns the signed download links under exports. The order matters: the XML is built from the same validated payload as the print, never from the PDF, so paper and file cannot disagree.

    1) document_create  ->  { documentId, letterId, previewUrl, totalCents, ... }
    2) order_send       ->  { orderId, status }            (letterId aus Schritt 1)
    3) document_get     ->  { exports: { zugferdPdfUrl, xrechnungXmlUrl } }
  3. 3

    What document_get returns

    exports has two slots with the same shape: available, url, code and message. When available is true, url is a signed link to the finished file, valid for seven days. The link is re-signed on every document_get, so you never have to store it, another call simply hands you a fresh one. If the file does not exist yet on the first read, FrankKi builds it inside that very call and answers with the finished result; that one call takes a little longer than the later ones.

    {
      "documentId": "9f1c...",
      "documentType": "rechnung",
      "documentNumber": "RE-2026-014",
      "letterId": "2b7e...",
      "orderId": "5a90...",
      "exports": {
        "zugferdPdfUrl": {
          "available": true,
          "url": "https://storage.frankki.app/...",
          "code": null,
          "message": null
        },
        "xrechnungXmlUrl": {
          "available": true,
          "url": "https://storage.frankki.app/...",
          "code": null,
          "message": null
        }
      }
    }
  4. 4

    What is inside the file

    The ZUGFeRD file is a PDF/A-3b with EN 16931 XML embedded, profile COMFORT. The embedded file is named factur-x.xml and carries the Data relationship the specification requires, so your recipient's accounting software finds it. The PDF is validated against veraPDF and the Mustang validator, the XML against the EN 16931 rules. Amounts are decimals in the XML and integer cents in the API. A credit note keeps the signs from its payload in the XML, even though the printed document shows amounts without a sign.

    ZUGFeRD PDF     PDF/A-3b, EN 16931 (COMFORT), profile id urn:cen.eu:en16931:2017
                    The embedded file is named factur-x.xml, AFRelationship = Data
                    XMP carries the ZUGFeRD marker, sRGB ICC profile, all fonts embedded
    XRechnung XML   the same data, standalone, with no PDF container
                    BT-24 carries the XRechnung 3.0 customization id instead of the bare EN 16931 profile id
  5. 5

    The XRechnung variant

    xrechnungXmlUrl serves the same data as a standalone XML file, with no PDF container. The only difference in content is BT-24, which carries the XRechnung 3.0 customization id instead of the bare EN 16931 profile id. Everything that belongs to the PDF container falls away: no factur-x.xml, no XMP, no PDF/A pass. Take XRechnung when a public body or a portal explicitly asks for XRechnung, and ZUGFeRD when a human should be able to read the invoice too.

  6. 6

    Which documents can export

    Invoices and credit notes only, and only after the letter has been sent. A dunning letter and a payment reminder repeat a claim that was already invoiced and are not invoices under EN 16931, so they never get a file. If you need an e-invoice there, it is the invoice the dunning letter refers to: call document_get on the referenced documentId.

  7. 7

    When there is no link, the slot says why

    When available is false, code names the reason, and the code tells you whether a second attempt is worth anything. DOCUMENT_EXPORT_NOT_SUPPORTED means never: the document type cannot carry an e-invoice, or you are working in sandbox mode where no real documents exist. Retrying changes nothing. DOCUMENT_EXPORT_NOT_READY means later: the letter has not been sent yet, or the feature is not enabled on your account yet. Send the letter and read again; never build a retry loop that keeps polling on NOT_SUPPORTED.

    {
      "exports": {
        "zugferdPdfUrl": {
          "available": false,
          "url": null,
          "code": "DOCUMENT_EXPORT_NOT_READY",
          "message": "Die E-Rechnung entsteht erst mit dem Versand. ..."
        },
        "xrechnungXmlUrl": {
          "available": false,
          "url": null,
          "code": "DOCUMENT_EXPORT_NOT_READY",
          "message": "Die E-Rechnung entsteht erst mit dem Versand. ..."
        }
      }
    }
  8. 8

    Retention

    Every generated e-invoice is also written into FrankKi's append-only archive, with a checksum and a hash chain, under the same rules as the letter itself and the proof of posting. That does not replace your own retention: German GoBD rules require YOU to keep the structured original. So download the file and put it in your archive; the download here is the convenient path to it, not an outsourcing of your duty.

  9. 9

    Check availability before you build on it

    The exports are being enabled gradually. Whether your account has them is visible without guessing, in the exports slot of any sent document: NOT_READY with the enablement hint means not yet. In the dashboard, the Dokumente list shows the same answer as download buttons with a reason. The full description of both error codes lives in the error catalog.

Structured letter content (blocks)See the tool referenceSee the error catalog

Trust and live status

Machine-readable service facts and the current operational status of the partner interface are publicly available at all times, no login needed.