Live

Converter API

Turn an existing e-invoice into another format: pass the source (XML or PDF), choose the target format, get the finished document back. The source format is detected; fields the target format does not carry are reported as conversionWarnings.

POST/api/v1/invoice/convert

How this differs from parse + generate

You can build the same result with two calls: parse returns the canonical invoice JSON, generate turns it into the target format. convert makes it one call — and returns two things the two-step route does not have: sourceFormat, the document it detected, and conversionWarnings, the fields the source carried that the target document does not. Billing works like a generate: the call needs the parse entitlement for the source format and the create entitlement for the target format, and counts once against the target's quota.

The source format is detected

There is no sourceFormat in the request: format and country are read from the document. When that cannot be decided reliably the service answers 400 FORMAT_NOT_DETECTED rather than guessing.

The target is checked

The generated document is checked against the rules of the target format. If it breaks one, you get a 422 with the rule codes (e.g. BR-DE-6) — instead of a document the recipient rejects.

PDF/A-3 included

For zugferd and facturx the result is a PDF/A-3 with embedded CII XML: mimeType is application/pdf, data is the base64 file.

Conversion matrix

Any document the parser recognises works as a source — XML or a ZUGFeRD/Factur-X PDF. There are exactly three target values; anything else is refused with a 400 that lists the allowed ones.

From (detected)To (targetFormat)
XRechnung 3.x (UBL / CII)
zugferdfacturxxrechnung
XRechnung 2.x
zugferdfacturxxrechnung
ZUGFeRD / Factur-X (PDF/A-3)
zugferdfacturxxrechnung
EN 16931 UBL / CII XML
zugferdfacturxxrechnung

The direction towards xrechnung is not symmetric: XRechnung → ZUGFeRD is lossless (CIUS → EN 16931), while the way back only succeeds when the German obligations are present in the source. Measured on 2026-09-15 it failed on BR-DE-6 — the seller's telephone number (BT-42), which ZUGFeRD does not require. The same class hits the Leitweg-ID (BT-10) on documents for public authorities.

Format not listed?

We build custom format conversions as commissioned work – e.g. proprietary ERP exports, legacy formats or industry-specific profiles. We scope feasibility, effort and timeline together with you.

Example

bash
1curl -X POST https://service.invoice-api.xhub.io/api/v1/invoice/convert \
2 -H "Authorization: Bearer sk_live_abc123..." \
3 -H "Content-Type: application/json" \
4 -d '{
5 "source": "<?xml version=\"1.0\"?>\n<ubl:Invoice xmlns:ubl=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\">...</ubl:Invoice>",
6 "targetFormat": "zugferd"
7 }'

Alternative: source as base64 (PDF or XML)

bash
1# Same endpoint, base64 source — this is the form to use for a
2# ZUGFeRD/Factur-X PDF, because a PDF is not a text body.
3curl -X POST https://service.invoice-api.xhub.io/api/v1/invoice/convert \
4 -H "Authorization: Bearer sk_live_abc123..." \
5 -H "Content-Type: application/json" \
6 -d "{\"source\": \"$(base64 -i rechnung-zugferd.pdf)\", \"targetFormat\": \"xrechnung\"}"

Response

Success

200 OK

Measured response for XRechnung (UBL) → ZUGFeRD. data is the base64 document, hash the SHA-256 over it (no prefix), filename the invoice number with the target format's extension. sourceFormat is what was detected — not something the call sent along.

json
1{
2 "success": true,
3 "sourceFormat": "XRECHNUNG_UBL",
4 "targetFormat": "zugferd",
5 "mimeType": "application/pdf",
6 "filename": "RE-2025-001.pdf",
7 "hash": "137429b56d6d01de076e7c03369df3c33218d98e688ea93b4b7b4fb97b20aa13",
8 "data": "JVBERi0xLjcKJYGBgYEKCjUgMCBvYmoKPDwKL0xlbmd0aCAxODA1...",
9 "conversionWarnings": []
10}

Target not conformant

422

Measured response for the way back: the same ZUGFeRD PDF towards xrechnung. complianceErrors names the rules that were broken — the information you need to fix the source document.

json
1{
2 "success": false,
3 "error": "CONVERSION_FAILED",
4 "message": "The source could not be converted to a conformant target document",
5 "targetFormat": "xrechnung",
6 "complianceErrors": [
7 {
8 "code": "BR-DE-6",
9 "message": "[BR-DE-6] Das Element \"Seller contact telephone number\" (BT-42) muss übermittelt werden.",
10 "field": ".../AccountingSupplierParty[1]/Party[1]/Contact[1]"
11 }
12 ],
13 "conversionWarnings": []
14}

Request parameters

ParameterTypeRequiredDescription
sourcestringThe source document: raw XML (the string starts with "<") or base64 of an XML or PDF file.
targetFormatstringTarget format: zugferd, facturx or xrechnung.
options.zugferdProfilestring-CII profile for zugferd and facturx: BASIC, EN16931 (default) or EXTENDED.

There are no other fields. Earlier versions of this page showed xml, sourceFormat, profile, validateSource, validateTarget and a multipart upload — the endpoint knows none of them.

Target format values

xrechnung

XRechnung 3.0.2 (UBL XML)

zugferd

ZUGFeRD 2.x (PDF/A-3)

facturx

Factur-X 1.0.x (PDF/A-3)

ZUGFeRD and Factur-X are the same Franco-German hybrid standard (PDF/A-3 with embedded EN 16931 XML). Which flavour is produced follows the seller's country (FR/BE → Factur-X, otherwise ZUGFeRD) — so both values yield the same PDF. Older versions are detected as a source; the target is always the current version.

ZUGFeRD profiles

For zugferd and facturx the profile decides which fields end up in the embedded XML. Without one, EN16931 is used.

BASIC

Basic information for automatic processing

EN16931

EU standard, recommended for B2G (default)

EXTENDED

All fields, maximum detail

MINIMUM and BASIC WL cannot be requested through the API: neither carries invoice lines, neither is EN 16931 conformant, and the specification treats them as a booking aid. Requesting one returns a 400 naming the three permitted profiles. Receiving and parsing such documents still works.

Error cases

StatusCodeDescription
400Bad Requestsource or targetFormat is missing, or targetFormat is none of the three values. A retired profile (MINIMUM, BASIC WL) is refused here too.
400FORMAT_NOT_DETECTEDThe source format could not be determined reliably; the response carries the detection object with its confidence.
403FORBIDDENAn entitlement is missing — the call needs the parse entitlement of the detected source format and the create entitlement of the target format.
422CONVERSION_FAILEDThe target document would not be conformant; complianceErrors names the rules.
429QUOTA_EXCEEDEDThe quota of the target key is exhausted.

When converting, the number of invoice line items is capped per plan, exactly as when generating — above the cap the API answers with HTTP 400 and TOO_MANY_LINE_ITEMS: Limits in the Creator API

Layout of the generated PDF

For zugferd and facturx the PDF is produced from a standard template; what counts is the embedded XML. For your own layout, the Visualizer API Planned Q4/2026

Typical use cases

XRechnung to ZUGFeRD

You have created XRechnung invoices for authorities and want to send the same invoices as PDF with embedded XML to business customers.

ZUGFeRD to XRechnung

You receive ZUGFeRD invoices from suppliers and need them as XRechnung — which works when the source carries the German obligations.

XRechnung 2.x to 3.x

Bring existing XRechnung invoices to the current version: the old version is detected as the source, the target is always the current one.

Factur-X to XRechnung

Prepare French Factur-X invoices for the German market and send them to public contracting authorities.

Step by step: XRechnung into ZUGFeRD

The recipe shows the same call with a complete sample invoice — including the point where the way back fails.

Custom conversions as commissioned work

From special format to production conversion: we analyze your source and target formats, build the adaptation and make it available to you through the API – optionally as part of an Enterprise package with its own SLA.