# ZUGFeRD to XRechnung Converter (`kamerozkan/zugferd-to-xrechnung-converter`) Actor

Assess supported ZUGFeRD documents for XRechnung conversion, request missing business terms, and emit target XML only after pinned target validation passes.

- **URL**: https://apify.com/kamerozkan/zugferd-to-xrechnung-converter.md
- **Developed by:** [Kamer Ozkan](https://apify.com/kamerozkan) (community)
- **Categories:** Developer tools
- **Stats:** 1 total users, 0 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

from $10.00 / 1,000 document processeds

This Actor is paid per event. You are not charged for the Apify platform usage, but only a fixed price for specific events.

Learn more: https://docs.apify.com/platform/actors/running/actors-in-store#pay-per-event

## What's an Apify Actor?

Actors are web data automations that power AI and operations. They run on the Apify platform to scrape websites, process data, connect APIs, and automate workflows.
In Batch mode, an Actor accepts a well-defined JSON input, performs an action which can take anything from a few seconds to a few hours,
and optionally produces a well-defined JSON output, datasets with results, or files in key-value store.
In Standby mode, an Actor provides a web server which can be used as a website, API, or an MCP server.
Actors are written with capital "A".

## How to integrate an Actor?

If asked about integration, you help developers integrate Actors into their projects.
You adapt to their stack and deliver integrations that are safe, well-documented, and production-ready.
The best way to integrate Actors is as follows.

- **AI agents and MCP clients** — the [Apify MCP server](https://docs.apify.com/integrations/mcp.md) at `https://mcp.apify.com` (remote, streamable HTTP, OAuth on first use).
- **Agentic workflows and local Actor development** — [Agent Skills](https://apify.com/.well-known/agent-skills/index.json) with the [Apify CLI](https://docs.apify.com/cli/docs.md): `npm install -g apify-cli`, then `apify login`.
- **JavaScript/TypeScript projects** — the official [JS/TS client](https://docs.apify.com/api/client/js/docs.md): `npm install apify-client`.
- **Python projects** — the official [Python client](https://docs.apify.com/api/client/python/docs.md): `pip install apify-client`.
- **Any other language** — the [REST API](https://docs.apify.com/api/v2.md).

For usage examples, see the [API](#api) section below.

For more details, see Apify documentation as [Markdown index](https://docs.apify.com/llms.txt) and [Markdown full-text](https://docs.apify.com/llms-full.txt).

# README

Convert supported ZUGFeRD or Factur-X CII content into a validated XRechnung
UBL or CII target.

### Outcome model

Every document ends in one explicit conversion state:

- `CONVERTED`: target XML was generated, parsed, validated by the pinned
  XRechnung rules, and found canonically equivalent after approved additions.
- `NEEDS_INPUT`: the source is usable, but mandatory target business terms are
  missing.
- `UNSUPPORTED`: the profile, version, target rule failure, or semantic gap is
  outside the automatic conversion matrix.
- `NOT_EVALUATED`: a required engine could not complete its assessment.

The Actor never emits a target artifact before target validation passes.

### Supported matrix

- Input container: hybrid PDF or direct CII XML.
- Current D16B source profiles: BASIC, EN16931, and EXTENDED only when the
  canonical transfer to the target can be proven.
- ZUGFeRD 1.0 BASIC, COMFORT, and EXTENDED documents receive an automatic,
  fail-closed upgrade attempt. The original legacy XML must first pass the
  pinned Mustangproject `2.24.0` source validator. The same digest-pinned
  engine then upgrades it to CII D16B before normalization and conversion.
- MINIMUM and BASIC WL are explicitly rejected as semantically insufficient.
- Target syntax: UBL 2.1 or CII D16B.
- Target rules: XRechnung `3.0.2`, configuration release `2026-01-31`.

For ZUGFeRD 1.0, the canonical migration comparison starts at the upgraded
D16B document. The result records `legacySourceToUpgradeIntegrity:
NOT_PROVEN`; Mustang's legacy XSLT is not presented as a lossless or universal
migration. Unsupported legacy shapes, invalid upgrade output, engine failures,
target validation failures, and semantic differences all fail closed.
The Actor will not claim that every historical ZUGFeRD document can be
upgraded automatically.

### Missing target data

KoSIT findings are translated into typed `missingInputs`. The safe override
allowlist covers buyer reference, selected seller/buyer identifiers and
addresses, seller contact data, and selected payment instruction terms.

Overrides:

- can add an absent allowlisted term only;
- can never replace an existing value;
- require a provenance reason;
- require a scheme identifier for electronic addresses;
- are validated by type and then by the target XRechnung engine;
- store the value as a SHA-256 in provenance, not as clear text.

If target validation exposes further missing terms, the result stays
`NEEDS_INPUT`. Unsupported semantic differences stay `UNSUPPORTED`.

When requested, the key-value store can retain the original PDF-extracted
legacy XML, the upgraded D16B intermediate, the validated target, and technical
reports as separate artifacts. Dataset evidence includes their hashes without
embedding invoice payloads.

### Product boundary

This is an assisted, evidence-driven migration pipeline. It does not invent
business data and does not make legal, tax, authenticity, signature, or
recipient acceptance decisions.

### Release state

The processing engine and Actor contract are feature-complete for the declared
matrix. The source contains a fail-closed pay-per-event charge path for
`document-processed` at exactly `$0.01` per evaluated conversion. Local
non-PPE results remain `billable: false`; a hosted run stops before processing
unless the event and price contract are active. The synthetic
`apify-actor-start` event is allowed, while `apify-default-dataset-item` must
cost USD 0. Apify Console configuration, a Docker image build, and hosted
lifecycle, charge-count, and budget-limit smoke tests remain before Store
publication.

# Actor input Schema

## `invoiceFiles` (type: `array`):

Upload hybrid PDF or supported CII XML files, including ZUGFeRD 1.0 documents for a fail-closed automatic upgrade attempt.

## `documents` (type: `array`):

Each item must contain exactly one source: url, xml, base64, or keyValueStoreKey.

## `sourceKeyValueStoreId` (type: `string`):

Key-value store ID containing records referenced by keyValueStoreKey.

## `sourceProfile` (type: `string`):

The profile is always detected from source evidence and cannot be overridden.

## `targetSyntax` (type: `string`):

Generate a validated XRechnung UBL or CII target.

## `targetRuleset` (type: `string`):

LATEST\_SUPPORTED resolves to the pinned XRechnung release recorded in the result.

## `overrides` (type: `array`):

Typed additions for missing target terms only. Existing values can never be replaced, and each value is recorded by hash in provenance.

## `storeConvertedXml` (type: `boolean`):

Store the validated target and, for a successful ZUGFeRD 1.0 upgrade, the D16B intermediate in the run key-value store.

## `storeExtractedXml` (type: `boolean`):

For PDF sources, store the extracted CII XML in the run key-value store.

## `storeTechnicalReports` (type: `boolean`):

Store source, PDF/A, and target validation reports in the run key-value store. Reports can contain invoice data.

## `maxFindingsPerDocument` (type: `integer`):

Maximum number of source and target validation findings returned for each document.

## Actor input object example

```json
{
  "documents": [
    {
      "documentId": "official-zugferd-sample",
      "fileName": "zugferd_2p0_EN16931_Einfach.pdf",
      "url": "https://raw.githubusercontent.com/ZUGFeRD/corpus/master/ZUGFeRDv2/correct/intarsys/EN16931/zugferd_2p0_EN16931_Einfach.pdf"
    }
  ],
  "sourceProfile": "AUTO",
  "targetSyntax": "UBL",
  "targetRuleset": "LATEST_SUPPORTED",
  "storeConvertedXml": true,
  "storeExtractedXml": false,
  "storeTechnicalReports": false,
  "maxFindingsPerDocument": 100
}
```

# Actor output Schema

## `results` (type: `string`):

Default Dataset rows validated against the versioned invoice, conversion, conformance, and semantic-difference contract.

## `summary` (type: `string`):

The OUTPUT key-value-store record with aggregate processing and billing counts.

## `artifacts` (type: `string`):

ARTIFACT-prefixed key-value-store records written only when artifact storage was requested.

# API

You can run this Actor programmatically using our API. Below are code examples in JavaScript, Python, and CLI, as well as the OpenAPI specification and MCP server setup.

## JavaScript example

```javascript
import { ApifyClient } from 'apify-client';

// Initialize the ApifyClient with your Apify API token
// Replace the '<YOUR_API_TOKEN>' with your token
const client = new ApifyClient({
    token: '<YOUR_API_TOKEN>',
});

// Prepare Actor input
const input = {
    "documents": [
        {
            "documentId": "official-zugferd-sample",
            "fileName": "zugferd_2p0_EN16931_Einfach.pdf",
            "url": "https://raw.githubusercontent.com/ZUGFeRD/corpus/master/ZUGFeRDv2/correct/intarsys/EN16931/zugferd_2p0_EN16931_Einfach.pdf"
        }
    ]
};

// Run the Actor and wait for it to finish
const run = await client.actor("kamerozkan/zugferd-to-xrechnung-converter").call(input);

// Fetch and print Actor results from the run's dataset (if any)
console.log('Results from dataset');
console.log(`💾 Check your data here: https://console.apify.com/storage/datasets/${run.defaultDatasetId}`);
const { items } = await client.dataset(run.defaultDatasetId).listItems();
items.forEach((item) => {
    console.dir(item);
});

// 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/js/docs

```

## Python example

```python
from apify_client import ApifyClient

# Initialize the ApifyClient with your Apify API token
# Replace '<YOUR_API_TOKEN>' with your token.
client = ApifyClient("<YOUR_API_TOKEN>")

# Prepare the Actor input
run_input = { "documents": [{
            "documentId": "official-zugferd-sample",
            "fileName": "zugferd_2p0_EN16931_Einfach.pdf",
            "url": "https://raw.githubusercontent.com/ZUGFeRD/corpus/master/ZUGFeRDv2/correct/intarsys/EN16931/zugferd_2p0_EN16931_Einfach.pdf",
        }] }

# Run the Actor and wait for it to finish
run = client.actor("kamerozkan/zugferd-to-xrechnung-converter").call(run_input=run_input)

# Fetch and print Actor results from the run's dataset (if there are any)
print(f"💾 Check your data here: https://console.apify.com/storage/datasets/{run.default_dataset_id}")
for item in client.dataset(run.default_dataset_id).iterate_items():
    print(item)

# 📚 Want to learn more 📖? Go to → https://docs.apify.com/api/client/python/docs/quick-start

```

## CLI example

```bash
echo '{
  "documents": [
    {
      "documentId": "official-zugferd-sample",
      "fileName": "zugferd_2p0_EN16931_Einfach.pdf",
      "url": "https://raw.githubusercontent.com/ZUGFeRD/corpus/master/ZUGFeRDv2/correct/intarsys/EN16931/zugferd_2p0_EN16931_Einfach.pdf"
    }
  ]
}' |
apify call kamerozkan/zugferd-to-xrechnung-converter --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,kamerozkan/zugferd-to-xrechnung-converter"
        }
    }
}

```

The hosted server signs you in with OAuth on first connect, so no API token belongs in this config. Clients without OAuth support can send an `Authorization: Bearer <APIFY_API_TOKEN>` header instead, using a token from API & Integrations in Apify Console (https://console.apify.com/settings/integrations).

## OpenAPI specification

Download the OpenAPI definition: https://api.apify.com/v2/actors/fxxpdIbB0WYcyISTK/builds/OiVFc4g0LBzdULIQ5/openapi.json
