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.
/api/v1/invoice/attachments/api/v1/pdf/attachmentsBeide 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
| Feld | Typ | Pflicht | Beschreibung |
|---|---|---|---|
pdf | string | Das Träger-PDF, Base64-kodiert. | |
attachments[] | array | Die einzubettenden Dateien, mindestens eine. | |
attachments[].filename | string | Der Name, der im Anhang-Fenster erscheint (max. 255 Zeichen). | |
attachments[].contentBase64 | string | Der Dateiinhalt, Base64-kodiert. | |
attachments[].mimeType | string | - | IANA-Medientyp der Datei (max. 127 Zeichen). |
attachments[].description | string | - | Beschreibung für den Leser (max. 255 Zeichen). |
attachments[].relationship | enum | - | PDF/A-3-AFRelationship: Data, Source, Alternative, Supplement oder Unspecified. Auf /invoice/attachments ist Supplement die Vorgabe. |
Beispiel
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 OK1{2 "success": true,3 "data": "JVBERi0xLjcKJeLjz9MK...",4 "pdfA3Conformant": true,5 "attachmentCount": 16}| Feld | Typ | Beschreibung |
|---|---|---|
success | boolean | true, wenn die Anhänge eingebettet wurden. |
data | string | Das Ergebnis-PDF, Base64-kodiert. |
pdfA3Conformant | boolean | true, wenn der Träger PDF/A-3 war und die Konformität erhalten blieb. |
attachmentCount | number | Anzahl 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.
| Status | Code | Beschreibung |
|---|---|---|
| 400 | TOO_MANY_ATTACHMENTS | Mehr Dateien als erlaubt (Vorgabe 20). |
| 400 | INVALID_PDF | Das Träger-PDF ließ sich nicht lesen. |
| 403 | FORBIDDEN | Die Berechtigung fehlt: pdf:invoice:attach für /invoice/attachments, pdf:document:attach für /pdf/attachments. |
| 413 | ATTACHMENT_TOO_LARGE | Eine einzelne Datei ist größer als erlaubt (Vorgabe 15 MB). |
| 413 | ATTACHMENTS_TOO_LARGE | Die Summe aller Dateien ist größer als erlaubt (Vorgabe 30 MB). |
| 429 | QUOTA_EXCEEDED | Das 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.
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