# UBL E-Invoice Technical Validator (`afkdigital/ubl-e-invoice-technical-validator`) Actor

Validate UBL 2.1 Invoice and CreditNote XML with official XSD/EN16931 and selected arithmetic rules. Separate schema/profile findings, JSON/CSV. No tax/network approval or signature checks.

- **URL**: https://apify.com/afkdigital/ubl-e-invoice-technical-validator.md
- **Developed by:** [AFK Digital](https://apify.com/afkdigital) (community)
- **Categories:** Developer tools
- **Security:** Limited permissions
- **Stats:** 2 total users, 1 monthly users, 100.0% runs succeeded, 0 bookmarks
- **User rating**: No ratings yet

## Pricing

$15.00 / 1,000 completed document validations

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/actors/running/actors-in-store.md#pay-per-event

## What's an Apify Actor?

An Actor is a serverless cloud program that runs on the Apify platform. It has two run modes.
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.

Apify vocabulary and the platform model are defined once, in the agent quickstart at https://apify.com/agents.md.

## 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.

Do not guess an integration path. Every one of them is in the agent quickstart at https://apify.com/agents.md: the Apify MCP server, Agent Skills with the Apify CLI, the JavaScript and Python clients, the REST API, and the account-free path for an agent with no human to sign in. It also carries the rule on stating cost before the first paid run.

For examples already wired to this Actor's own input schema, see the [API](#api) section below.

Each client library has reference documentation the quickstart does not restate: [JavaScript/TypeScript](https://docs.apify.com/api/client/js/docs.md) (`npm install apify-client`) and [Python](https://docs.apify.com/api/client/python/docs.md) (`pip install apify-client`).

# README

## UBL E-Invoice Technical Validator

Validate a UBL 2.1 **Invoice** or **CreditNote** before importing it into your accounting or integration pipeline. Receive separate XML/security, XSD, profile and arithmetic findings, JSON/CSV exports and a summary. **One document per run.**

**Technical validation only.** A successful result is not Peppol certification, tax-authority acceptance, network delivery or legal approval. **Digital signatures and certificates are not verified.** Nothing is submitted to a tax system or invoice network.

### Supported versions and profiles — release 1.0.0

| validationProfile | Schema | Additional checks |
|---|---|---|
| UBL-2.1-XSD | OASIS UBL 2.1 final (2013-11-04), Invoice/CreditNote | XML safety and XSD only. No business or monetary conclusion. |
| EN16931-1.3.17 | Same XSD | Official ConnectingEurope EN 16931 UBL artifacts 1.3.17 (2026-10-12), unmodified compiled XSLT with bundled Schematron/code lists. |
| EN16931-1.3.17+AFK-1.0 (default) | Same XSD | Official EN rules plus separately identified AFK line calculation, positive price-base quantity and currency consistency checks. A selected technical profile, not an official CIUS. |

The current OASIS UBL release is 2.5 (2026-08-12); this product deliberately supports only the tested UBL 2.1 binding required by the bundled EN rules. Newer UBL versions and other document types are rejected. Peppol BIS, XRechnung, UBL-TR/GIB, ZATCA, FatturaPA, self-billing and country-specific tax acceptance are **not supported**. Official EN rules do not contain Peppol/country CIUS rules. Current Peppol documentation was checked; that package is not bundled or executed.

A document may pass EN-only and fail the stricter AFK profile. One official example has a positive quantity and negative line net amount. The original file is preserved: EN-only accepts it; AFK-LINE-01 identifies the inconsistent quantity/price calculation.

### Input

Supply **exactly one** source:

- **xmlText**: XML as a string. Use file upload for originals with non-UTF-8 declarations.
- **xmlFile**: one XML uploaded with the Console file picker, or its HTTPS Apify key-value-store record URL. Only https://api.apify.com/v2/key-value-stores/.../records/... is accepted. No arbitrary servers, redirects, compressed files or archives.

| Field | Values/default |
|---|---|
| documentType | auto (default), Invoice, CreditNote; explicit type must match exact root and namespace |
| schemaVersion | 2.1 only |
| validationProfile | Exact identifier from the profile table |
| maxFindings | Integer 1–500, default 100. Limits returned findings, never the underlying validity decision. Summary retains full counts and truncation status. |

The prefilled runnable example is official EN sample-discount-price.xml, with a price discount and four-decimal net unit price. **Clear the prefilled xmlText when uploading a file.** An API request must supply one source; empty API input is not silently replaced with a demo invoice.

### Validation and arithmetic

1. XML/security: well-formedness, exact namespace, structural limits, forbidden DTD/entities/XInclude/processing instructions.
2. XSD: full locally packaged normative OASIS 2.1 schemas. Invoice-provided schemaLocation never selects/fetches a schema. XSD failure skips profile/arithmetic execution explicitly.
3. Profile: selected official EN assertions, with official rule IDs and source XPath locations from SVRL.
4. Arithmetic: official BR-CO-10–17, tax-category and decimal rules check line-total sums, document allowances/charges, VAT breakdowns, exclusive/inclusive totals, prepayments, payable rounding and payable amount. **The pinned official rules and tolerances are used unchanged.**
5. Only in +AFK-1.0:
   - AFK-LINE-01: line net equals round(quantity × net PriceAmount / BaseQuantity + line charges − line allowances, 2). BaseQuantity defaults to 1. CreditNote uses CreditedQuantity. Price-level discounts are already reflected in net PriceAmount and are not subtracted twice.
   - AFK-BASE-01: price BaseQuantity greater than zero.
   - AFK-CURRENCY-01: monetary currency matches DocumentCurrencyCode, except a separate declared TaxCurrencyCode tax total.
   - AFK decimal calculations use exact decimal arithmetic and XPath-style rounding, half ties toward positive infinity. Exact cent equality for line totals is a selected AFK rule, not a Peppol tolerance claim.

For common total rules, expected_value and actual_value contain amounts. For other profile rules expected_value contains the official assertion expression; actual_value may be null where no single scalar is unambiguous. XSD-prefixed findings contain native schema diagnostics. A clean XSD-only report means only schema validity.

### Outputs

Dataset: one row per returned finding; zero-finding documents get a CHECK-PASSED informational row.

| Field | Meaning |
|---|---|
| document_id | SHA-256-derived document identifier |
| invoice_number | UBL cbc:ID when safely parsed |
| validation_layer | xml, security, xsd, profile, arithmetic, configuration, technical or summary |
| rule_id | XSD diagnostic, official EN rule or AFK-prefixed rule |
| severity | error, warning or info |
| field_path | XML/XPath location |
| message | Explanation |
| expected_value / actual_value | Amounts/assertion evidence where available; otherwise null |
| schema_version / ruleset_version | Exact selected versions |

Run storage:

- REPORT: complete JSON report and layer status.
- FINDINGS: JSON array.
- FINDINGS-CSV: CSV with stable headers; spreadsheet formula prefixes neutralized with a leading apostrophe. JSON preserves original scalar values.
- SUMMARY: counts, truncation, completion, scope and billing policy.
- DELIVERY-STATE: billing/delivery state; charged is 1/0, or null for an uncertain billing response.
- SOURCE-DISTRIBUTION: source ZIP with program, original rule sources, schemas, licenses and build files.

A technical/retrieval/resource failure has completed=false, billable=false and an explicit failed run. A malformed, XSD-invalid, profile-invalid or security-rejected document can still receive a **completed technical report** and is chargeable.

### Price

**$0.015 per completed document validation — $15 per 1,000.** Only document-validated, count 1 per completed report. Invalid completed reports have the same price. Findings are not billed individually. No start fee, automatic Dataset-row fee or separately passed-through platform usage fee.

Technical failures, unreachable uploads, unsupported options and resource-limit failures do not trigger a validation charge. REPORT, JSON, CSV, SUMMARY and Dataset delivery are stored before charging. Same-run retries/resurrections do not attempt another charge or append duplicate rows. Uncertain charge responses are never retried on resurrection, favoring underbilling. A deliberately started independent run is a new validation request even for the same XML; there is no cross-run free document cache.

Apify account subscriptions/credits and taxes follow Apify terms. Live Store pricing is authoritative.

### Security, privacy and limits

- XML: **2 MiB**, **64 element levels**, **30,000 elements**.
- Worker: **30 seconds wall**, **20 seconds CPU**, **384 MiB resident-memory guard**; 64 file descriptors. Actor: **512 MiB** container and 120-second default timeout.
- Uploads: 5-second socket timeout and 20-second loop deadline; no redirects/decompression.
- DTDs/external entities disabled and rejected. XInclude and processing instructions rejected. Saxon external protocols and extension functions disabled. Only trusted packaged XSD/XSLT execute.
- Original invoice contents are not logged or copied into report files. Reports necessarily contain invoice ID and diagnostic field values. Apify input/upload and report storage follow your account's access/retention settings. Delete confidential records when no longer needed.
- No OCR/PDF extraction, attachment malware scan, signature/certificate checks, economic-transaction verification, or invoice-network submission.

### Sources, licenses and reproducibility

Verified 2026-11-06. No schema/rule download at validation time. Individual SHA-256 hashes in vendor/manifest.json.

- [OASIS UBL 2.1 final](https://docs.oasis-open.org/ubl/os-UBL-2.1/). Original notices retained in unchanged schemas and bundled specification HTML.
- [EN16931 1.3.17 release](https://github.com/ConnectingEurope/eInvoicing-EN16931/releases/tag/validation-1.3.17), **EUPL-1.2**. Original Schematron, code lists, XSLT and 18 in-limit examples included unchanged. The original 19-document corpus also includes one 3.2 MiB example, correctly rejected by the 2 MiB resource guard and retained in local test evidence. Archive SHA-256: bf02a0e3f6cbe692a4a28e70be7bdcaded5612b4169b543e13d6cb4f33c29e92.
- Program: EUPL-1.2, see LICENSE. Original components retain their notices. Complete source available from Actor source and each run's SOURCE-DISTRIBUTION.
- [lxml](https://lxml.de/validation.html) 6.1.3 (BSD-3-Clause plus libxml/libxslt notices); [SaxonC-HE](https://www.saxonica.com/html/saxon-c/index.html) 13.1.1 (MPL-2.0, no commercial key for HE); [Apify Python SDK](https://docs.apify.com/sdk/python) 4.2.1 (Apache-2.0). Locked dependencies and upstream links in docs/SOURCES.json.
- [Apify pay-per-event documentation](https://docs.apify.com/actors/monetize/pay-per-event).

### Tests and local reproduction

Official OASIS Invoice/CreditNote examples; official EN Invoice/CreditNote/discount-price documents; controlled missing field, totals, allowance/charge, VAT, currency, quantity and base-quantity errors; prepayment/rounding; negative-line profile distinction; truncation; malformed/UTF-16 DTD, entity, XInclude, namespace spoof, size/depth limits; real worker timeout/RSS limits; upload restrictions; invalid-report billing, free technical/storage failures and replay/ambiguous-charge handling.

Create a Python environment, install requirements-lock.txt, and run python -m pytest -q. These tests assess this packaged release, not every jurisdiction's legal requirements.

# Actor input Schema

## `xmlText` (type: `string`):

Exactly one source, at most 2 MiB. Clear this field when uploading xmlFile.

## `xmlFile` (type: `string`):

An HTTPS Apify key-value-store upload URL. Clear xmlText. No arbitrary servers/redirects.

## `documentType` (type: `string`):

Exact UBL root type; auto detects Invoice or CreditNote. Explicit selection must match.

## `schemaVersion` (type: `string`):

Only the tested OASIS UBL 2.1 normative schema is supported.

## `validationProfile` (type: `string`):

AFK adds stricter line/currency checks. No Peppol or country tax acceptance.

## `maxFindings` (type: `integer`):

Counts/validity reflect every detected issue.

## Actor input object example

```json
{
  "xmlText": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<!--\n\n    Licensed under European Union Public Licence (EUPL) version 1.2.\n\n-->\n<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"\n    xmlns:cbc=\"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\"\n    xmlns:cac=\"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\">\n    <cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>\n    <cbc:ProfileID>P1</cbc:ProfileID>\n    <cbc:ID>test decimal 1</cbc:ID>\n    <cbc:IssueDate>2018-02-05</cbc:IssueDate>\n    <cbc:DueDate>2018-02-28</cbc:DueDate>\n    <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>\n    <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>\n    <cbc:TaxCurrencyCode>EUR</cbc:TaxCurrencyCode>\n    <cac:AccountingSupplierParty>\n        <cac:Party>\n            <cac:PartyIdentification>\n                <cbc:ID>46830600751</cbc:ID>\n            </cac:PartyIdentification>\n            <cac:PostalAddress>\n                <cbc:StreetName>ULICA 1</cbc:StreetName>\n                <cbc:CityName>SPLIT</cbc:CityName>\n                <cbc:PostalZone>10000</cbc:PostalZone>\n                <cac:AddressLine>\n                    <cbc:Line>ULICA 1, 10000 SPLIT</cbc:Line>\n                </cac:AddressLine>\n                <cac:Country>\n                    <cbc:IdentificationCode>HR</cbc:IdentificationCode>\n                </cac:Country>\n            </cac:PostalAddress>\n            <cac:PartyTaxScheme>\n                <cbc:CompanyID>HR46830600751</cbc:CompanyID>\n                <cac:TaxScheme>\n                    <cbc:ID>VAT</cbc:ID>\n                </cac:TaxScheme>\n            </cac:PartyTaxScheme>\n            <cac:PartyLegalEntity>\n                <cbc:RegistrationName>HEP SPLIT</cbc:RegistrationName>\n                <cbc:CompanyID>086374645</cbc:CompanyID>\n            </cac:PartyLegalEntity>\n        </cac:Party>\n    </cac:AccountingSupplierParty>\n    <cac:AccountingCustomerParty>\n        <cac:Party>\n            <cac:PartyIdentification>\n                <cbc:ID>12346830600751</cbc:ID>\n            </cac:PartyIdentification>\n            <cac:PostalAddress>\n                <cbc:StreetName>VUKOVARSKA PROMJENA ADRESE</cbc:StreetName>\n                <cbc:CityName>ZAGREB</cbc:CityName>\n                <cbc:PostalZone>10000</cbc:PostalZone>\n                <cac:AddressLine>\n                    <cbc:Line>VUKOVARSKA PROMJENA ADRESE 20, 10000 ZAGREB</cbc:Line>\n                </cac:AddressLine>\n                <cac:Country>\n                    <cbc:IdentificationCode>HR</cbc:IdentificationCode>\n                </cac:Country>\n            </cac:PostalAddress>\n            <cac:PartyTaxScheme>\n                <cbc:CompanyID>HR46830600751</cbc:CompanyID>\n                <cac:TaxScheme>\n                    <cbc:ID>VAT</cbc:ID>\n                </cac:TaxScheme>\n            </cac:PartyTaxScheme>\n            <cac:PartyLegalEntity>\n                <cbc:RegistrationName>HEP-OPERATOR DISTRIBUCIJSKOG SUSTAVA D.O.O. ZA DISTRIBUCIJU I\n                    OPSKRBU ELEKTRICNE ENERGIJE</cbc:RegistrationName>\n                <cbc:CompanyID>08634543</cbc:CompanyID>\n            </cac:PartyLegalEntity>\n        </cac:Party>\n    </cac:AccountingCustomerParty>\n    <cac:PaymentMeans>\n        <cbc:PaymentMeansCode>4</cbc:PaymentMeansCode>\n    </cac:PaymentMeans>\n    <cac:TaxTotal>\n        <cbc:TaxAmount currencyID=\"EUR\">3.03</cbc:TaxAmount>\n        <cac:TaxSubtotal>\n            <cbc:TaxableAmount currencyID=\"EUR\">12.12</cbc:TaxableAmount>\n            <cbc:TaxAmount currencyID=\"EUR\">3.03</cbc:TaxAmount>\n            <cac:TaxCategory>\n                <cbc:ID>S</cbc:ID>\n                <cbc:Percent>25</cbc:Percent>\n                <cac:TaxScheme>\n                    <cbc:ID>VAT</cbc:ID>\n                </cac:TaxScheme>\n            </cac:TaxCategory>\n        </cac:TaxSubtotal>\n    </cac:TaxTotal>\n    <cac:LegalMonetaryTotal>\n        <cbc:LineExtensionAmount currencyID=\"EUR\">12.12</cbc:LineExtensionAmount>\n        <cbc:TaxExclusiveAmount currencyID=\"EUR\">12.12</cbc:TaxExclusiveAmount>\n        <cbc:TaxInclusiveAmount currencyID=\"EUR\">15.15</cbc:TaxInclusiveAmount>\n        <cbc:PayableAmount currencyID=\"EUR\">15.15</cbc:PayableAmount>\n    </cac:LegalMonetaryTotal>\n    <cac:InvoiceLine>\n        <cbc:ID>1</cbc:ID>\n        <cbc:InvoicedQuantity unitCode=\"EA\">100.000</cbc:InvoicedQuantity>\n        <cbc:LineExtensionAmount currencyID=\"EUR\">12.12</cbc:LineExtensionAmount>\n        <cac:Item>\n            <cbc:Name>stavka 1</cbc:Name>\n            <cac:OriginCountry>\n                <cbc:IdentificationCode>HR</cbc:IdentificationCode>\n            </cac:OriginCountry>\n            <cac:ClassifiedTaxCategory>\n                <cbc:ID>S</cbc:ID>\n                <cbc:Percent>25</cbc:Percent>\n                <cac:TaxScheme>\n                    <cbc:ID>VAT</cbc:ID>\n                </cac:TaxScheme>\n            </cac:ClassifiedTaxCategory>\n        </cac:Item>\n        <cac:Price>\n            <cbc:PriceAmount currencyID=\"EUR\">0.1212</cbc:PriceAmount>\n            <cbc:BaseQuantity unitCode=\"EA\">1</cbc:BaseQuantity>\n            <cac:AllowanceCharge>\n                <cbc:ChargeIndicator>false</cbc:ChargeIndicator>\n                <cbc:Amount currencyID=\"EUR\">0.0022</cbc:Amount>\n                <cbc:BaseAmount currencyID=\"EUR\">0.1234</cbc:BaseAmount>\n            </cac:AllowanceCharge>\n        </cac:Price>\n    </cac:InvoiceLine>\n</Invoice>\n",
  "documentType": "auto",
  "schemaVersion": "2.1",
  "validationProfile": "EN16931-1.3.17+AFK-1.0",
  "maxFindings": 100
}
```

# Actor output Schema

## `report` (type: `string`):

No description

## `findings` (type: `string`):

No description

## `csv` (type: `string`):

No description

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

No description

## `source` (type: `string`):

No description

## `dataset` (type: `string`):

No description

# 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 = {
    "xmlText": `<?xml version="1.0" encoding="UTF-8"?>
<!--

    Licensed under European Union Public Licence (EUPL) version 1.2.

-->
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
    xmlns:cbc="urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2"
    xmlns:cac="urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2">
    <cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
    <cbc:ProfileID>P1</cbc:ProfileID>
    <cbc:ID>test decimal 1</cbc:ID>
    <cbc:IssueDate>2018-02-05</cbc:IssueDate>
    <cbc:DueDate>2018-02-28</cbc:DueDate>
    <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
    <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
    <cbc:TaxCurrencyCode>EUR</cbc:TaxCurrencyCode>
    <cac:AccountingSupplierParty>
        <cac:Party>
            <cac:PartyIdentification>
                <cbc:ID>46830600751</cbc:ID>
            </cac:PartyIdentification>
            <cac:PostalAddress>
                <cbc:StreetName>ULICA 1</cbc:StreetName>
                <cbc:CityName>SPLIT</cbc:CityName>
                <cbc:PostalZone>10000</cbc:PostalZone>
                <cac:AddressLine>
                    <cbc:Line>ULICA 1, 10000 SPLIT</cbc:Line>
                </cac:AddressLine>
                <cac:Country>
                    <cbc:IdentificationCode>HR</cbc:IdentificationCode>
                </cac:Country>
            </cac:PostalAddress>
            <cac:PartyTaxScheme>
                <cbc:CompanyID>HR46830600751</cbc:CompanyID>
                <cac:TaxScheme>
                    <cbc:ID>VAT</cbc:ID>
                </cac:TaxScheme>
            </cac:PartyTaxScheme>
            <cac:PartyLegalEntity>
                <cbc:RegistrationName>HEP SPLIT</cbc:RegistrationName>
                <cbc:CompanyID>086374645</cbc:CompanyID>
            </cac:PartyLegalEntity>
        </cac:Party>
    </cac:AccountingSupplierParty>
    <cac:AccountingCustomerParty>
        <cac:Party>
            <cac:PartyIdentification>
                <cbc:ID>12346830600751</cbc:ID>
            </cac:PartyIdentification>
            <cac:PostalAddress>
                <cbc:StreetName>VUKOVARSKA PROMJENA ADRESE</cbc:StreetName>
                <cbc:CityName>ZAGREB</cbc:CityName>
                <cbc:PostalZone>10000</cbc:PostalZone>
                <cac:AddressLine>
                    <cbc:Line>VUKOVARSKA PROMJENA ADRESE 20, 10000 ZAGREB</cbc:Line>
                </cac:AddressLine>
                <cac:Country>
                    <cbc:IdentificationCode>HR</cbc:IdentificationCode>
                </cac:Country>
            </cac:PostalAddress>
            <cac:PartyTaxScheme>
                <cbc:CompanyID>HR46830600751</cbc:CompanyID>
                <cac:TaxScheme>
                    <cbc:ID>VAT</cbc:ID>
                </cac:TaxScheme>
            </cac:PartyTaxScheme>
            <cac:PartyLegalEntity>
                <cbc:RegistrationName>HEP-OPERATOR DISTRIBUCIJSKOG SUSTAVA D.O.O. ZA DISTRIBUCIJU I
                    OPSKRBU ELEKTRICNE ENERGIJE</cbc:RegistrationName>
                <cbc:CompanyID>08634543</cbc:CompanyID>
            </cac:PartyLegalEntity>
        </cac:Party>
    </cac:AccountingCustomerParty>
    <cac:PaymentMeans>
        <cbc:PaymentMeansCode>4</cbc:PaymentMeansCode>
    </cac:PaymentMeans>
    <cac:TaxTotal>
        <cbc:TaxAmount currencyID="EUR">3.03</cbc:TaxAmount>
        <cac:TaxSubtotal>
            <cbc:TaxableAmount currencyID="EUR">12.12</cbc:TaxableAmount>
            <cbc:TaxAmount currencyID="EUR">3.03</cbc:TaxAmount>
            <cac:TaxCategory>
                <cbc:ID>S</cbc:ID>
                <cbc:Percent>25</cbc:Percent>
                <cac:TaxScheme>
                    <cbc:ID>VAT</cbc:ID>
                </cac:TaxScheme>
            </cac:TaxCategory>
        </cac:TaxSubtotal>
    </cac:TaxTotal>
    <cac:LegalMonetaryTotal>
        <cbc:LineExtensionAmount currencyID="EUR">12.12</cbc:LineExtensionAmount>
        <cbc:TaxExclusiveAmount currencyID="EUR">12.12</cbc:TaxExclusiveAmount>
        <cbc:TaxInclusiveAmount currencyID="EUR">15.15</cbc:TaxInclusiveAmount>
        <cbc:PayableAmount currencyID="EUR">15.15</cbc:PayableAmount>
    </cac:LegalMonetaryTotal>
    <cac:InvoiceLine>
        <cbc:ID>1</cbc:ID>
        <cbc:InvoicedQuantity unitCode="EA">100.000</cbc:InvoicedQuantity>
        <cbc:LineExtensionAmount currencyID="EUR">12.12</cbc:LineExtensionAmount>
        <cac:Item>
            <cbc:Name>stavka 1</cbc:Name>
            <cac:OriginCountry>
                <cbc:IdentificationCode>HR</cbc:IdentificationCode>
            </cac:OriginCountry>
            <cac:ClassifiedTaxCategory>
                <cbc:ID>S</cbc:ID>
                <cbc:Percent>25</cbc:Percent>
                <cac:TaxScheme>
                    <cbc:ID>VAT</cbc:ID>
                </cac:TaxScheme>
            </cac:ClassifiedTaxCategory>
        </cac:Item>
        <cac:Price>
            <cbc:PriceAmount currencyID="EUR">0.1212</cbc:PriceAmount>
            <cbc:BaseQuantity unitCode="EA">1</cbc:BaseQuantity>
            <cac:AllowanceCharge>
                <cbc:ChargeIndicator>false</cbc:ChargeIndicator>
                <cbc:Amount currencyID="EUR">0.0022</cbc:Amount>
                <cbc:BaseAmount currencyID="EUR">0.1234</cbc:BaseAmount>
            </cac:AllowanceCharge>
        </cac:Price>
    </cac:InvoiceLine>
</Invoice>`
};

// Run the Actor and wait for it to finish
const run = await client.actor("afkdigital/ubl-e-invoice-technical-validator").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 = { "xmlText": """<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<!--

    Licensed under European Union Public Licence (EUPL) version 1.2.

-->
<Invoice xmlns=\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\"
    xmlns:cbc=\"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\"
    xmlns:cac=\"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\">
    <cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>
    <cbc:ProfileID>P1</cbc:ProfileID>
    <cbc:ID>test decimal 1</cbc:ID>
    <cbc:IssueDate>2018-02-05</cbc:IssueDate>
    <cbc:DueDate>2018-02-28</cbc:DueDate>
    <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>
    <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>
    <cbc:TaxCurrencyCode>EUR</cbc:TaxCurrencyCode>
    <cac:AccountingSupplierParty>
        <cac:Party>
            <cac:PartyIdentification>
                <cbc:ID>46830600751</cbc:ID>
            </cac:PartyIdentification>
            <cac:PostalAddress>
                <cbc:StreetName>ULICA 1</cbc:StreetName>
                <cbc:CityName>SPLIT</cbc:CityName>
                <cbc:PostalZone>10000</cbc:PostalZone>
                <cac:AddressLine>
                    <cbc:Line>ULICA 1, 10000 SPLIT</cbc:Line>
                </cac:AddressLine>
                <cac:Country>
                    <cbc:IdentificationCode>HR</cbc:IdentificationCode>
                </cac:Country>
            </cac:PostalAddress>
            <cac:PartyTaxScheme>
                <cbc:CompanyID>HR46830600751</cbc:CompanyID>
                <cac:TaxScheme>
                    <cbc:ID>VAT</cbc:ID>
                </cac:TaxScheme>
            </cac:PartyTaxScheme>
            <cac:PartyLegalEntity>
                <cbc:RegistrationName>HEP SPLIT</cbc:RegistrationName>
                <cbc:CompanyID>086374645</cbc:CompanyID>
            </cac:PartyLegalEntity>
        </cac:Party>
    </cac:AccountingSupplierParty>
    <cac:AccountingCustomerParty>
        <cac:Party>
            <cac:PartyIdentification>
                <cbc:ID>12346830600751</cbc:ID>
            </cac:PartyIdentification>
            <cac:PostalAddress>
                <cbc:StreetName>VUKOVARSKA PROMJENA ADRESE</cbc:StreetName>
                <cbc:CityName>ZAGREB</cbc:CityName>
                <cbc:PostalZone>10000</cbc:PostalZone>
                <cac:AddressLine>
                    <cbc:Line>VUKOVARSKA PROMJENA ADRESE 20, 10000 ZAGREB</cbc:Line>
                </cac:AddressLine>
                <cac:Country>
                    <cbc:IdentificationCode>HR</cbc:IdentificationCode>
                </cac:Country>
            </cac:PostalAddress>
            <cac:PartyTaxScheme>
                <cbc:CompanyID>HR46830600751</cbc:CompanyID>
                <cac:TaxScheme>
                    <cbc:ID>VAT</cbc:ID>
                </cac:TaxScheme>
            </cac:PartyTaxScheme>
            <cac:PartyLegalEntity>
                <cbc:RegistrationName>HEP-OPERATOR DISTRIBUCIJSKOG SUSTAVA D.O.O. ZA DISTRIBUCIJU I
                    OPSKRBU ELEKTRICNE ENERGIJE</cbc:RegistrationName>
                <cbc:CompanyID>08634543</cbc:CompanyID>
            </cac:PartyLegalEntity>
        </cac:Party>
    </cac:AccountingCustomerParty>
    <cac:PaymentMeans>
        <cbc:PaymentMeansCode>4</cbc:PaymentMeansCode>
    </cac:PaymentMeans>
    <cac:TaxTotal>
        <cbc:TaxAmount currencyID=\"EUR\">3.03</cbc:TaxAmount>
        <cac:TaxSubtotal>
            <cbc:TaxableAmount currencyID=\"EUR\">12.12</cbc:TaxableAmount>
            <cbc:TaxAmount currencyID=\"EUR\">3.03</cbc:TaxAmount>
            <cac:TaxCategory>
                <cbc:ID>S</cbc:ID>
                <cbc:Percent>25</cbc:Percent>
                <cac:TaxScheme>
                    <cbc:ID>VAT</cbc:ID>
                </cac:TaxScheme>
            </cac:TaxCategory>
        </cac:TaxSubtotal>
    </cac:TaxTotal>
    <cac:LegalMonetaryTotal>
        <cbc:LineExtensionAmount currencyID=\"EUR\">12.12</cbc:LineExtensionAmount>
        <cbc:TaxExclusiveAmount currencyID=\"EUR\">12.12</cbc:TaxExclusiveAmount>
        <cbc:TaxInclusiveAmount currencyID=\"EUR\">15.15</cbc:TaxInclusiveAmount>
        <cbc:PayableAmount currencyID=\"EUR\">15.15</cbc:PayableAmount>
    </cac:LegalMonetaryTotal>
    <cac:InvoiceLine>
        <cbc:ID>1</cbc:ID>
        <cbc:InvoicedQuantity unitCode=\"EA\">100.000</cbc:InvoicedQuantity>
        <cbc:LineExtensionAmount currencyID=\"EUR\">12.12</cbc:LineExtensionAmount>
        <cac:Item>
            <cbc:Name>stavka 1</cbc:Name>
            <cac:OriginCountry>
                <cbc:IdentificationCode>HR</cbc:IdentificationCode>
            </cac:OriginCountry>
            <cac:ClassifiedTaxCategory>
                <cbc:ID>S</cbc:ID>
                <cbc:Percent>25</cbc:Percent>
                <cac:TaxScheme>
                    <cbc:ID>VAT</cbc:ID>
                </cac:TaxScheme>
            </cac:ClassifiedTaxCategory>
        </cac:Item>
        <cac:Price>
            <cbc:PriceAmount currencyID=\"EUR\">0.1212</cbc:PriceAmount>
            <cbc:BaseQuantity unitCode=\"EA\">1</cbc:BaseQuantity>
            <cac:AllowanceCharge>
                <cbc:ChargeIndicator>false</cbc:ChargeIndicator>
                <cbc:Amount currencyID=\"EUR\">0.0022</cbc:Amount>
                <cbc:BaseAmount currencyID=\"EUR\">0.1234</cbc:BaseAmount>
            </cac:AllowanceCharge>
        </cac:Price>
    </cac:InvoiceLine>
</Invoice>
""" }

# Run the Actor and wait for it to finish
run = client.actor("afkdigital/ubl-e-invoice-technical-validator").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 '{
  "xmlText": "<?xml version=\\"1.0\\" encoding=\\"UTF-8\\"?>\\n<!--\\n\\n    Licensed under European Union Public Licence (EUPL) version 1.2.\\n\\n-->\\n<Invoice xmlns=\\"urn:oasis:names:specification:ubl:schema:xsd:Invoice-2\\"\\n    xmlns:cbc=\\"urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2\\"\\n    xmlns:cac=\\"urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2\\">\\n    <cbc:CustomizationID>urn:cen.eu:en16931:2017</cbc:CustomizationID>\\n    <cbc:ProfileID>P1</cbc:ProfileID>\\n    <cbc:ID>test decimal 1</cbc:ID>\\n    <cbc:IssueDate>2018-02-05</cbc:IssueDate>\\n    <cbc:DueDate>2018-02-28</cbc:DueDate>\\n    <cbc:InvoiceTypeCode>380</cbc:InvoiceTypeCode>\\n    <cbc:DocumentCurrencyCode>EUR</cbc:DocumentCurrencyCode>\\n    <cbc:TaxCurrencyCode>EUR</cbc:TaxCurrencyCode>\\n    <cac:AccountingSupplierParty>\\n        <cac:Party>\\n            <cac:PartyIdentification>\\n                <cbc:ID>46830600751</cbc:ID>\\n            </cac:PartyIdentification>\\n            <cac:PostalAddress>\\n                <cbc:StreetName>ULICA 1</cbc:StreetName>\\n                <cbc:CityName>SPLIT</cbc:CityName>\\n                <cbc:PostalZone>10000</cbc:PostalZone>\\n                <cac:AddressLine>\\n                    <cbc:Line>ULICA 1, 10000 SPLIT</cbc:Line>\\n                </cac:AddressLine>\\n                <cac:Country>\\n                    <cbc:IdentificationCode>HR</cbc:IdentificationCode>\\n                </cac:Country>\\n            </cac:PostalAddress>\\n            <cac:PartyTaxScheme>\\n                <cbc:CompanyID>HR46830600751</cbc:CompanyID>\\n                <cac:TaxScheme>\\n                    <cbc:ID>VAT</cbc:ID>\\n                </cac:TaxScheme>\\n            </cac:PartyTaxScheme>\\n            <cac:PartyLegalEntity>\\n                <cbc:RegistrationName>HEP SPLIT</cbc:RegistrationName>\\n                <cbc:CompanyID>086374645</cbc:CompanyID>\\n            </cac:PartyLegalEntity>\\n        </cac:Party>\\n    </cac:AccountingSupplierParty>\\n    <cac:AccountingCustomerParty>\\n        <cac:Party>\\n            <cac:PartyIdentification>\\n                <cbc:ID>12346830600751</cbc:ID>\\n            </cac:PartyIdentification>\\n            <cac:PostalAddress>\\n                <cbc:StreetName>VUKOVARSKA PROMJENA ADRESE</cbc:StreetName>\\n                <cbc:CityName>ZAGREB</cbc:CityName>\\n                <cbc:PostalZone>10000</cbc:PostalZone>\\n                <cac:AddressLine>\\n                    <cbc:Line>VUKOVARSKA PROMJENA ADRESE 20, 10000 ZAGREB</cbc:Line>\\n                </cac:AddressLine>\\n                <cac:Country>\\n                    <cbc:IdentificationCode>HR</cbc:IdentificationCode>\\n                </cac:Country>\\n            </cac:PostalAddress>\\n            <cac:PartyTaxScheme>\\n                <cbc:CompanyID>HR46830600751</cbc:CompanyID>\\n                <cac:TaxScheme>\\n                    <cbc:ID>VAT</cbc:ID>\\n                </cac:TaxScheme>\\n            </cac:PartyTaxScheme>\\n            <cac:PartyLegalEntity>\\n                <cbc:RegistrationName>HEP-OPERATOR DISTRIBUCIJSKOG SUSTAVA D.O.O. ZA DISTRIBUCIJU I\\n                    OPSKRBU ELEKTRICNE ENERGIJE</cbc:RegistrationName>\\n                <cbc:CompanyID>08634543</cbc:CompanyID>\\n            </cac:PartyLegalEntity>\\n        </cac:Party>\\n    </cac:AccountingCustomerParty>\\n    <cac:PaymentMeans>\\n        <cbc:PaymentMeansCode>4</cbc:PaymentMeansCode>\\n    </cac:PaymentMeans>\\n    <cac:TaxTotal>\\n        <cbc:TaxAmount currencyID=\\"EUR\\">3.03</cbc:TaxAmount>\\n        <cac:TaxSubtotal>\\n            <cbc:TaxableAmount currencyID=\\"EUR\\">12.12</cbc:TaxableAmount>\\n            <cbc:TaxAmount currencyID=\\"EUR\\">3.03</cbc:TaxAmount>\\n            <cac:TaxCategory>\\n                <cbc:ID>S</cbc:ID>\\n                <cbc:Percent>25</cbc:Percent>\\n                <cac:TaxScheme>\\n                    <cbc:ID>VAT</cbc:ID>\\n                </cac:TaxScheme>\\n            </cac:TaxCategory>\\n        </cac:TaxSubtotal>\\n    </cac:TaxTotal>\\n    <cac:LegalMonetaryTotal>\\n        <cbc:LineExtensionAmount currencyID=\\"EUR\\">12.12</cbc:LineExtensionAmount>\\n        <cbc:TaxExclusiveAmount currencyID=\\"EUR\\">12.12</cbc:TaxExclusiveAmount>\\n        <cbc:TaxInclusiveAmount currencyID=\\"EUR\\">15.15</cbc:TaxInclusiveAmount>\\n        <cbc:PayableAmount currencyID=\\"EUR\\">15.15</cbc:PayableAmount>\\n    </cac:LegalMonetaryTotal>\\n    <cac:InvoiceLine>\\n        <cbc:ID>1</cbc:ID>\\n        <cbc:InvoicedQuantity unitCode=\\"EA\\">100.000</cbc:InvoicedQuantity>\\n        <cbc:LineExtensionAmount currencyID=\\"EUR\\">12.12</cbc:LineExtensionAmount>\\n        <cac:Item>\\n            <cbc:Name>stavka 1</cbc:Name>\\n            <cac:OriginCountry>\\n                <cbc:IdentificationCode>HR</cbc:IdentificationCode>\\n            </cac:OriginCountry>\\n            <cac:ClassifiedTaxCategory>\\n                <cbc:ID>S</cbc:ID>\\n                <cbc:Percent>25</cbc:Percent>\\n                <cac:TaxScheme>\\n                    <cbc:ID>VAT</cbc:ID>\\n                </cac:TaxScheme>\\n            </cac:ClassifiedTaxCategory>\\n        </cac:Item>\\n        <cac:Price>\\n            <cbc:PriceAmount currencyID=\\"EUR\\">0.1212</cbc:PriceAmount>\\n            <cbc:BaseQuantity unitCode=\\"EA\\">1</cbc:BaseQuantity>\\n            <cac:AllowanceCharge>\\n                <cbc:ChargeIndicator>false</cbc:ChargeIndicator>\\n                <cbc:Amount currencyID=\\"EUR\\">0.0022</cbc:Amount>\\n                <cbc:BaseAmount currencyID=\\"EUR\\">0.1234</cbc:BaseAmount>\\n            </cac:AllowanceCharge>\\n        </cac:Price>\\n    </cac:InvoiceLine>\\n</Invoice>\\n"
}' |
apify call afkdigital/ubl-e-invoice-technical-validator --silent --output-dataset

```

## MCP server setup

```json
{
    "mcpServers": {
        "apify": {
            "type": "http",
            "url": "https://mcp.apify.com/?tools=fetch-actor-details,afkdigital/ubl-e-invoice-technical-validator"
        }
    }
}
```

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/P9Creh6g2x0tMtBYx/builds/Rjnpe7xJI9qUEf8QG/openapi.json
