Live

Attachments API

Dateien in ein bestehendes PDF einbetten — Leistungsnachweis, Prüfbericht, Stundenzettel. Der Empfänger findet sie im Anhang-Fenster seines PDF-Betrachters. War der Träger ein PDF/A-3 (ZUGFeRD/Factur-X), bleibt die Konformität erhalten.

POST/api/v1/invoice/attachments
POST/api/v1/pdf/attachments

Beide Pfade nehmen denselben Request und liefern dieselbe Antwort. Der Unterschied ist die Berechtigung, gegen die abgerechnet wird: /invoice/attachments verlangt pdf:invoice:attach, /pdf/attachments verlangt pdf:document:attach. Zusätzlich setzt /invoice/attachments die Vorgabe relationship: „Supplement“; auf /pdf/attachments bleibt das Feld leer, wenn du es nicht angibst.

Das macht aus einem PDF keine ZUGFeRD-Rechnung

Dieser Endpunkt hängt Dateien an — nichts weiter. Ein eigenes PDF wird dadurch nicht zur E-Rechnung: ZUGFeRD ist mehr als „XML im PDF“.

  • · Es entstehen keine XMP-Metadaten (fx-Namensraum). Ein empfangendes System sucht dort zuerst und findet nichts.
  • · Ein einfaches PDF wird nicht zu PDF/A-3 umgewandelt; die Antwort sagt das mit pdfA3Conformant: false.
  • · Der Anhang wird nicht als Rechnungs-XML gekennzeichnet — die Rechnung bleibt das sichtbare PDF, nicht der Anhang.

Request

FeldTypPflichtBeschreibung
pdfstringDas Träger-PDF, Base64-kodiert.
attachments[]arrayDie einzubettenden Dateien, mindestens eine.
attachments[].filenamestringDer Name, der im Anhang-Fenster erscheint (max. 255 Zeichen).
attachments[].contentBase64stringDer Dateiinhalt, Base64-kodiert.
attachments[].mimeTypestring-IANA-Medientyp der Datei (max. 127 Zeichen).
attachments[].descriptionstring-Beschreibung für den Leser (max. 255 Zeichen).
attachments[].relationshipenum-PDF/A-3-AFRelationship: Data, Source, Alternative, Supplement oder Unspecified. Auf /invoice/attachments ist Supplement die Vorgabe.

Beispiel

bash
1curl -X POST https://service.invoice-api.xhub.io/api/v1/invoice/attachments \
2 -H "Authorization: Bearer sk_live_abc123..." \
3 -H "Content-Type: application/json" \
4 -d '{
5 "pdf": "JVBERi0xLjcKJeLjz9MK...",
6 "attachments": [
7 {
8 "filename": "leistungsnachweis.pdf",
9 "mimeType": "application/pdf",
10 "contentBase64": "JVBERi0xLjQKJc...",
11 "description": "Stundennachweis März 2026",
12 "relationship": "Supplement"
13 }
14 ]
15 }'

Response

200 OK
json
1{
2 "success": true,
3 "data": "JVBERi0xLjcKJeLjz9MK...",
4 "pdfA3Conformant": true,
5 "attachmentCount": 1
6}
FeldTypBeschreibung
successbooleantrue, wenn die Anhänge eingebettet wurden.
datastringDas Ergebnis-PDF, Base64-kodiert.
pdfA3Conformantbooleantrue, wenn der Träger PDF/A-3 war und die Konformität erhalten blieb.
attachmentCountnumberAnzahl der eingebetteten Dateien.

Grenzen

20

Dateien je Request

15 MB

je Datei

30 MB

über alle Dateien eines Requests

Die Grenzen sind serverseitig konfigurierbar; die genannten Werte sind die Vorgaben des Dienstes. Zusätzlich kann der Betrieb die erlaubten Medientypen einschränken — dann wird ein nicht erlaubter Typ mit 400 MIME_NOT_ALLOWED abgewiesen.

StatusCodeBeschreibung
400TOO_MANY_ATTACHMENTSMehr Dateien als erlaubt (Vorgabe 20).
400INVALID_PDFDas Träger-PDF ließ sich nicht lesen.
403FORBIDDENDie Berechtigung fehlt: pdf:invoice:attach für /invoice/attachments, pdf:document:attach für /pdf/attachments.
413ATTACHMENT_TOO_LARGEEine einzelne Datei ist größer als erlaubt (Vorgabe 15 MB).
413ATTACHMENTS_TOO_LARGEDie Summe aller Dateien ist größer als erlaubt (Vorgabe 30 MB).
429QUOTA_EXCEEDEDDas Kontingent des Schlüssels ist erschöpft.

Der andere Weg: Anhänge beim Erzeugen

Wenn die Rechnung erst entsteht, gehören Anhänge in die Rechnungsdaten selbst: das Feld invoice.attachments[] (BG-24, BT-122 bis BT-125) wird beim Erzeugen als EmbeddedDocumentBinaryObject in das XML geschrieben. Dieser Endpunkt hier ist für den anderen Fall — das PDF existiert schon.

json
1{
2 "invoice": {
3 "invoiceNumber": "RE-2026-001",
4 ...
5 "attachments": [
6 {
7 "filename": "leistungsnachweis.pdf",
8 "mimeType": "application/pdf",
9 "content": "JVBERi0xLjQKJc...",
10 "description": "Stundennachweis März 2026"
11 }
12 ]
13 }
14}

Unterschied in einem Satz: invoice.attachments[] landet im XML der Rechnung, /attachments hängt Dateien an die PDF-Datei. Das Feld heißt dort content, hier contentBase64, und mimeType ist dort Pflicht.

Creator API