Attach a proof of performance to the invoice

Your customer wants the timesheet with the invoice — in the same file, not in a second email.

Steps

  1. 1

    Take the carrier PDF: the ZUGFeRD or Factur-X file a generate or convert call returned. Only a PDF/A-3 carrier keeps its conformance.

  2. 2

    Base64-encode the proof and put it into attachments[] as contentBase64, together with filename, mimeType, description and relationship: Supplement (the default on this route anyway).

  3. 3

    The key needs the pdf:invoice:attach entitlement. It is granted per API key; without it the service answers 403 and "Missing entitlement: pdf:invoice:attach" — measured on 2026-09-15. If your key does not have it, ask us for it; the plans are on the pricing page.

  4. 4

    The response carries the finished PDF in data (base64), plus pdfA3Conformant and attachmentCount. Decode it, store it, send it.

The call

POST /api/v1/invoice/attachments

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

Long base64 values are cut short here (…). Put your own files in their place — the carrier PDF and the attachment.

Where this goes wrong

Two places. The carrier must be PDF/A-3 — otherwise the answer says pdfA3Conformant: false: the attachments are in the file, but the file is no longer a conformant archival document. And attaching does not turn an arbitrary PDF into a ZUGFeRD invoice: no fx XMP metadata is written, and the attachment is not marked as the invoice XML. If you need an e-invoice, generate or convert one.