LiveZUGFeRD / Factur-X

Your layout, our XML

You already have your invoice PDF — from your ERP, your print shop, your own template. This endpoint takes it as the carrier, generates the CII XML from your invoice data and returns that same PDF with the XML inside it as factur-x.xml.

POST/api/v1/invoice/{countryCode}/{format}/embed

The difference from /generate

Both endpoints produce the same e-invoice from the same data and run on the same entitlement. The only difference is the page the recipient sees.

  • • With /generate the visual page comes from our template — then PDF/A-3 conformance is our problem.
  • • With /embed the visual page comes from you and stays as it is; we only place the XML inside and set the markers.
  • • Same invoice data, same validation chain, same failure modes (422 with the same rule codes).

There is no template or templateId on this route. The body is strict and rejects them with a 400 rather than ignoring them silently — the layout is yours.

To the Creator API (/generate)

Hybrid formats only

A hybrid document needs a visual page a carrier PDF can stand in for. XML-only formats such as xrechnung or ubl have none, and plain pdf carries no XML — both return 400.

Path parameters

FieldTypeRequiredDescription
countryCodestringCountry of the hybrid format — de, ch, fr or be.
formatstringThe hybrid format: zugferd for DE and CH, facturx for FR and BE.

Request

FieldTypeRequiredDescription
pdfstring (base64)Your carrier PDF, base64-encoded. It becomes the visual page of the hybrid document.
invoiceobjectThe invoice data the XML is generated from — the same shape as /generate, with the same mandatory fields.
validateboolean-Also runs the XSD and Schematron check and returns the verdict in the validation block. Costs a second unit, exactly as on /generate.
formatOptions.profilestring-ZUGFeRD / Factur-X profile, EN16931 by default.
formatOptions.versionstring-Format version, 2.4 for ZUGFeRD and 1.08 for Factur-X by default.

PDF/A-3 is declared, not converted

We set the marker on the carrier you sent. We do not rewrite your PDF. On an arbitrary PDF that declaration can therefore be wrong.

  • • Most commonly when your PDF uses fonts without an embedded font file — which PDF/A-3 requires.
  • • What we actually checked is listed in carrier.checks; what we found, in carrier.warnings.
  • • A full PDF/A-3b proof (veraPDF) does not take place here. Nothing is rejected because of it: the finding is ours, the decision is yours.

If your recipient enforces a full proof: run your carrier through a PDF/A converter once before it reaches us — or use /generate, where the PDF is ours.

Example

bash
1curl -X POST https://service.invoice-api.xhub.io/api/v1/invoice/de/zugferd/embed \
2 -H "Authorization: Bearer sk_live_abc123..." \
3 -H "Content-Type: application/json" \
4 -d '{
5 "pdf": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlL1BhZ2UvTWVkaWFCb3...",
6 "validate": true,
7 "invoice": {
8 "invoiceNumber": "RE-2025-001",
9 "type": "invoice",
10 "issueDate": "2025-01-15",
11 "dueDate": "2025-02-15",
12 "currency": "EUR",
13 "seller": {
14 "name": "Meine Firma GmbH",
15 "street": "Musterstraße 1",
16 "city": "Berlin",
17 "postalCode": "10115",
18 "countryCode": "DE",
19 "vatId": "DE123456789",
20 "bankAccount": {
21 "iban": "DE89370400440532013000",
22 "bic": "COBADEFFXXX"
23 }
24 },
25 "buyer": {
26 "name": "Kunde AG",
27 "street": "Kundenweg 42",
28 "city": "München",
29 "postalCode": "80331",
30 "countryCode": "DE",
31 "vatId": "DE987654321"
32 },
33 "countrySpecific": {
34 "countryCode": "DE",
35 "buyerReference": "BUYER-REF-001"
36 },
37 "items": [
38 {
39 "position": 1,
40 "description": "Beratungsleistung",
41 "quantity": 10,
42 "unit": "HUR",
43 "unitPrice": 150.00,
44 "taxRate": 19,
45 "taxCategoryCode": "S",
46 "netAmount": 1500.00,
47 "taxAmount": 285.00,
48 "grossAmount": 1785.00
49 }
50 ],
51 "subtotal": 1500.00,
52 "total": 1785.00,
53 "taxSummary": [
54 {
55 "taxRate": 19,
56 "netAmount": 1500.00,
57 "taxAmount": 285.00
58 }
59 ]
60 }
61 }'

Response

200 OK
json
1{
2 "success": true,
3 "format": "zugferd",
4 "filename": "RE-2025-001.pdf",
5 "mimeType": "application/pdf",
6 "hash": "9f2c4e1b7a0d5836f4b2c9e18a7d3045c6b1e8f29a4d70b3c5e81f6a2d9c4b70",
7 "payloadHash": "3a7f1e9c2b8d4056a1c7e3f9b2d84e6015c9a7f3e1b8d2460c5a9f7e3b1d8460",
8 "data": "JVBERi0xLjQKJeLjz9MKMyAwIG9iago8PC9UeXBlL1BhZ2Uv...",
9 "embeddedXml": "<?xml version=\"1.0\" encoding=\"UTF-8\"?><rsm:CrossIndustryInvoice ...",
10 "carrier": {
11 "pdfA3Declared": true,
12 "checks": [
13 { "code": "PDF-001", "severity": "error", "passed": true },
14 { "code": "XMP-003", "severity": "warning", "passed": true }
15 ],
16 "warnings": [
17 {
18 "code": "CARRIER_FONTS_NOT_EMBEDDED",
19 "message": "The carrier uses 2 fonts without an embedded font file."
20 }
21 ]
22 },
23 "validation": {
24 "valid": true,
25 "status": "passed",
26 "results": [
27 { "format": "zugferd-2.4-en16931", "valid": true, "errors": [] }
28 ]
29 },
30 "appliedFormatOptions": {
31 "version": "2.4",
32 "profile": "EN16931"
33 }
34}
FieldTypeDescription
successbooleanWhether the hybrid document was produced.
formatstringThe output format used.
filenamestringSuggested filename.
mimeTypestringMIME type of the returned document.
hashstringSHA-256 of the returned bytes, hex-encoded. Not stable across calls, because the PDF carries a creation timestamp — use payloadHash for idempotent names.
payloadHashstringSHA-256 of the canonical JSON of your invoice data — the stable key for idempotent calls. hash changes on every call because the PDF carries a timestamp.
datastring (base64)The hybrid document, base64-encoded: your layout with the generated XML inside.
embeddedXmlstringThe embedded CII XML in plain text, for convenient inspection.
carrierobjectWhat we measured on the document we produced — a finding, not a claim.
validationobjectThe conformance verdict — present only when the request set validate: true.
appliedFormatOptionsobjectThe version and profile the document was actually written in: yours, or the defaults.

The carrier block

FieldTypeDescription
pdfA3Declaredbooleantrue means we set the PDF/A-3 marker on your carrier (XMP pdfaid:part=3, conformance B, sRGB output intent). It does not mean your carrier is conformant.
checksarrayThe individual checks, each with code, severity (warning, error, fatal), passed and, where there is one, message.
warningsarrayFindings about the carrier you sent that we report but do not reject on — for example CARRIER_FONTS_NOT_EMBEDDED.

The validation block

Present only if you sent validate: true. status says what happened: passed — the rulebooks ran and found nothing; failed — they found something, valid is then false and errors names it; not_run — they did not run completely, valid is null and reason says why (missing, load-failed, transform-failed or not-bound). A not_run is not a pass: it proves nothing about the document.

Billing

The call runs on the format's existing create entitlement and costs one unit — two if you set validate: true. No new entitlement, no surcharge.

Errors

StatusCodeDescription
400Bad RequestThe country/format pair is not a hybrid format — an XML-only format or pdf has no visual page.
400Bad Requesttemplate or templateId was sent. Neither exists on this route.
400INVALID_PDFThe carrier is not a readable PDF.
401UNAUTHORIZEDAPI key missing or invalid.
403FORBIDDENThe key does not hold the format's create entitlement.
413PAYLOAD_TOO_LARGEThe carrier PDF is larger than the configured limit.
422UNPROCESSABLEThe invoice data cannot be turned into a conforming e-invoice — the same body as /generate, with errors and complianceErrors and without data.
429QUOTA_EXCEEDEDThe format's quota is exhausted.