Skip to content

Ironfang Finance

Validate, understand, fix

Check Peppol BIS Billing 3, XRechnung and ZUGFeRD / Factur-X invoices and credit notes against their exact published rulesets.

Ironfang Finance checks structured e-invoices against the exact published rules for their format and reports every finding with its original rule identifier. Try it in the browser without an account, or run the same checks from your own code.

New to e-invoice formats and rules? Explore the e-invoicing learning hub for the basics, guided paths and the free validators.

Choose your format

Every format is checked the same way: the document passes through its layers in order, each result names the ruleset that checked it, and a service failure is never reported as an invalid invoice. What goes in, and what the checks cover, depends on the format.

The e-invoice formats Ironfang Finance validates
FamilyInputChecks and details
Peppol BIS Billing 3A UBL 2.1 invoice or credit note, as XMLXML, the UBL schema, EN 16931 and the Peppol rules: the Peppol validation pipeline. Try the Peppol validator.
XRechnungAn invoice or credit note in UBL 2.1 or UN/CEFACT CII, as XMLXML, the schema of its syntax, EN 16931 and the XRechnung rules: the XRechnung guide. Try the XRechnung validator.
ZUGFeRD / Factur-XA hybrid PDF with its invoice XML embedded, or the CII XML on its ownA PDF adds PDF/A and attachment checks to the XML checks. What the XML checks establish depends on the profile: MINIMUM and BASIC WL do not carry a complete EN 16931 invoice. See the ZUGFeRD / Factur-X guide, and try the ZUGFeRD / Factur-X validator.

The API validates Peppol through V1 or V2, and XRechnung and ZUGFeRD / Factur-X through V2; the V1 and V2 guide sets out which serves what and how their results differ.

Try it in the browser

Each free validator works in the browser without an account. Anonymous documents and results are not kept.

  1. Open the validator for your format, then try its sample or upload your own document.
  2. Read the verdict and each layer. A service failure is not an invalid invoice.
  3. Follow a rule explanation where one exists, fix your source document and validate it again.

Open the Peppol validatorSee a complete example invoice

Other formats: XRechnung or ZUGFeRD / Factur-X, each also in German. The Peppol validator also downloads the result as JSON and as a readable report you can print or save as a PDF.

The Peppol XML invoice example walks through a valid sample field by field, reconciles its totals and shows a broken copy with its two findings and the fix. To read an invoice rather than check it, the free XML invoice viewer opens a UBL invoice or credit note as a readable document, and the XRechnung viewer does the same for XRechnung in UBL or CII.

Validate from code

This quickstart validates the published Peppol BIS Billing 3 sample invoice through version 2 of the Finance API and keeps the result. You need bash, curl and sha256sum, and a free Ironfang account.

1. Create a scoped API key

In the portal, open Developers, API keys and create a key with the Validate and generate e-invoices scope, finance:einvoices:write. The secret is shown once. Keep it in the IRONFANG_API_KEY environment variable, never in a script or a repository. No account yet? Create a free one.

2. Download the sample invoice

The sample invoice is a complete, fictional Peppol BIS Billing 3 invoice in UBL, the one the Peppol validator offers:

curl --fail --silent --show-error --output invoice.xml https://ironfang.com/samples/peppol-bis-billing-3-invoice-v1.xml

3. Validate it

Save this script as validate-peppol.sh and run bash validate-peppol.sh invoice.xml. It names the family, so a document that declares another is refused rather than checked as something else, and it derives the Idempotency-Key from the file, so a retry returns the first result and is not charged again.

#!/usr/bin/env bash
# Validate one Peppol BIS Billing 3 invoice with the Ironfang Finance API
# (V2) and keep the result.
#
#   IRONFANG_API_KEY=... ./validate-peppol.sh invoice.xml
#
# The result is written to result.json. A completed validation exits 0 and
# prints its outcome, valid or invalid. A request or service problem exits
# non-zero and leaves the Problem in result.json. A retry with the same file
# sends the same Idempotency-Key, so it returns the first result and is not
# charged again.
set -euo pipefail
file="$1"
base="${IRONFANG_FINANCE_API:-https://api.ironfang.com/finance}"
key="peppol-$(sha256sum "$file" | cut -c1-40)"

curl --fail-with-body --silent --show-error \
  "$base/v2/einvoices/validate?family=peppol-bis-billing-3" \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/xml" \
  -H "Idempotency-Key: $key" \
  --data-binary "@$file" \
  --output result.json

grep -o '"outcome":"[a-z]*"' result.json | head -n 1

4. Read the response

The script prints "outcome":"valid" and keeps the whole result in result.json. Abridged, with the engines and timing left out:

{
  "schema": "ironfang/finance/einvoice/validation-result/v2",
  "operation_id": "01929a8e-0000-7000-8000-000000000000",
  "status": "completed",
  "outcome": "valid",
  "input": {
    "media_type": "application/xml",
    "document_type": "invoice"
  },
  "ruleset": {
    "requested": "latest",
    "id": "fwrs_pub_invoice_2026_5",
    "family": "peppol-bis-billing-3",
    "selection_method": "latest",
    "official_release": "2026.5 (May 2026 release, aka BIS Billing 3.0.21)"
  },
  "coverage": {"scope": "xml", "checked": ["input", "xml", "xsd", "en16931", "peppol"], "not_checked": []},
  "layers": [
    {"layer": "input", "status": "passed", "fatal": 0, "warning": 0, "information": 0},
    {"layer": "xml", "status": "passed", "fatal": 0, "warning": 0, "information": 0},
    {"layer": "xsd", "status": "passed", "fatal": 0, "warning": 0, "information": 0},
    {"layer": "en16931", "status": "passed", "fatal": 0, "warning": 0, "information": 0},
    {"layer": "peppol", "status": "passed", "fatal": 0, "warning": 0, "information": 0}
  ],
  "counts": {"by_severity": {"fatal": 0, "warning": 0, "information": 0}},
  "findings": [],
  "usage": {"charged": true, "credits": 1}
}

ruleset names the exact release that checked the document, layers reports each check in order and usage shows the one validation charged to your allowance. A signed-in result is kept for 30 days at GET /finance/v2/einvoices/results/{id}, where the id is its operation_id.

Valid, invalid or no verdict

  • Valid: HTTP 200, status completed, outcome valid. Warnings can still be listed; they never fail a document.
  • Invalid: HTTP 200, status completed, outcome invalid. Each entry in findings has its rule id, layer, severity and location, and counts.by_severity.fatal is above zero. Fix the source document and validate again; the rule reference explains the common rules.
  • No verdict: any other status is a Problem (application/problem+json) with a code. The script exits non-zero and keeps it in result.json. A 4xx is about the request or the account, such as the key, the size, the family or the document type: fix it before retrying, or for a 429 wait until the limit clears. validator_unavailable, validation_timeout and internal_error carry outcome indeterminate: nothing was established, nothing is charged, and the same request can be retried.

Next

XRechnung and ZUGFeRD / Factur-X use the same route with their own family: the XRechnung API section and the ZUGFeRD / Factur-X API section each have a tested script, the ZUGFeRD one for PDFs as well as XML. The V2 OpenAPI contract has every parameter and field, and the API reference below lists the scopes and endpoints.

Results and rules

A result reports each layer in order. A failed prerequisite leaves the later layers skipped rather than passed. Only fatal findings fail a document; warnings stay visible even when the verdict is valid. The official rules decide validity, and validation never repairs your XML.

The validation rule reference explains 142 rules one page each: what failed, the likely causes, the fix, and a before and after taken from documents run through the same engine as the validator. Look a rule up by its code, a business term such as BT-106, or an XML element. Rules without an explanation keep their engine finding and identifier; findings in the validator link to an explanation wherever one exists.

Open the rule reference

Some places to start:

Beyond one validation

Once validation runs from your code, these build on it.

Generation

Generation creates Peppol BIS Billing 3 UBL, an invoice or a credit note, from structured generation-input/v1 JSON. It does not create XRechnung or ZUGFeRD / Factur-X documents. The exact final bytes must pass the selected production validator before they are returned, base64 encoded with their SHA-256; a failure returns no invoice, and Ironfang Finance never bypasses a rule to make one pass. The invoice JSON playground tries it in the browser, and the generation guide has the schema and four runnable quickstarts. Generating through an account needs a paid plan.

Jobs and batches

Job and batch endpoints take validation or generation with an Ironfang Finance write key, return a job ID for polling, and keep the selected ruleset across retries. Read keys retrieve metadata and completed results. Cancellation keeps work that already completed. A completed validation is valid or invalid; service failures stay indeterminate and uncharged. Durable jobs use the same engines and do not transmit invoices or add legal certification.

Webhooks and delivery

Accounts can configure signed event webhooks and S3-compatible artifact delivery as separate destinations. Each destination has its own retry history; a delivery failure does not change a verdict or charge for another validation. Verify webhook signatures and deduplicate event identifiers at your receiver.

S3 qualification covers SeaweedFS 4.46 in the tested configuration; other providers need their own checks. PDFs and signed report ZIPs are not exported automatically. Delivery to your endpoint or bucket does not prove recipient acceptance, accounting ingestion or payment, and does not send the invoice over Peppol.

Saved results and privacy

Anonymous documents and results are processed transiently. When signed in or using an API key, result JSON and findings are stored for 30 days, and you can delete them sooner. Synchronous validation does not retain the uploaded document. Durable API jobs retain encrypted input until completion, cancellation or 24-hour expiry cleanup. Backups follow their own retention policy. Authenticated generated XML is retained with its result for 30 days. Downloaded copies stay under your control.

After deletion or expiry, a small operation record retains hashes, ruleset, outcome, timestamps and usage metadata until organisation erasure. This stops an old retry from running or charging again: reusing its Idempotency-Key returns 410 result_gone, so request a new validation with a new key only when you mean to. Signed reports turn a retained result into verifiable evidence.

Peppol validation pipeline

How a Peppol BIS Billing 3 document is checked. UBL is the XML document syntax, EN 16931 defines the core semantics of an electronic invoice, and Peppol BIS Billing adds its usage rules. Ironfang Finance sends the supplied XML bytes to its self-hosted Java service, where PHIVE runs the registered upstream validation artefacts, using Saxon for their XSLT checks. XRechnung and ZUGFeRD / Factur-X run their own layers, listed in their guides.

  1. XML well-formedness: the document must parse safely. Malformed XML is distinct from a business-rule failure.
  2. UBL schema: the Invoice or CreditNote must have the structure and data types its UBL schema defines.
  3. EN 16931: upstream artefacts check the applicable semantic and calculation rules.
  4. Peppol: upstream BIS Billing artefacts check the applicable profile and usage rules.
  5. Service failures: timeouts, unavailable validators and internal failures are indeterminate. They do not establish whether the invoice is valid.

Which versions checked my document?

Each result names its exact ruleset and engine. The live ruleset registry lists VESIDs, document types, specification releases, checksums and lifecycle dates. Newer validators also provide a runtime object with the validator, PHIVE, phive-rules, phive-rules-peppol and Saxon versions, the upstream VES name and deprecation status.

Runtime metadata is a verified observation at observed_at, not a live readiness guarantee. Older retained validators may omit it. Library versions and specification releases are separate identities; an upstream validity date is included only when PHIVE supplies one. The registry lifecycle label sendable selects the active release for latest; it does not mean Ironfang Finance can send an invoice.

The standards, rule sets and open-source libraries behind every check, with their licences and where their source is published, are listed on licences and acknowledgements.

API reference

Send the platform API key as a Bearer token. Validate with POST /finance/v2/einvoices/validate, for every format, or POST /finance/v1/einvoices/validate, for Peppol. Validation, generation and deletion need finance:einvoices:write; reading results needs finance:einvoices:read; authenticated ruleset reads need finance:einvoices:rulesets:read. V1 lists its results at /finance/v1/einvoices/results and gets or deletes one by operation ID; V2 lists V1 and V2 results together, as the V1 and V2 guide explains. The Ironfang MCP server has 3 Ironfang Finance tools. Reference only: what a validation rule means and how to fix it, and which rulesets the validator runs. Validating and generating documents, results and jobs are REST-only; the Ironfang Finance API takes a platform API key and has no OAuth delegation yet.

V2 OpenAPI contract - V1 OpenAPI contract - API keys and integration examples - Privacy policy

Run in PostmanView the collection

The collection is generated from the OpenAPI contract and opens with three requests that need no credential: list the rulesets, validate a sample invoice and generate one from JSON. You can also download it. Keep API keys in a private environment or vault and select the invoice files you intend to send.

SDKs and plans

SDKs, CLI and GitHub Action

Python and TypeScript validation SDKs, a Python CLI and the official GitHub Action are publicly released as v0.2.0. They cover Invoice and CreditNote validation against a selected ruleset through V1, and through V2 Peppol BIS Billing 3, XRechnung and ZUGFeRD / Factur-X as XML or hybrid PDF, with V2 jobs, batches and deliveries, and distinct outcomes for valid documents, invalid documents and service failures. Find installation instructions and the pinned public Action reference in the integration guide. Install TypeScript from npm or download the Python release from GitHub.

Create free API account

Free and paid plans

Free accounts include 250 validations per UTC calendar month, with no card required. Authenticated generation requires a paid Build, Pro or Platform subscription. Paid plans share one allowance between validation and generation, following the monthly subscription period. Compare the current prices and allowances.

Paid plans serve UK and EU businesses, including sole traders. UK VAT numbers are optional. EU automatic checkout requires a verified VAT number and matching business details; businesses without a VAT number, or with verified details needing review, require approval before payment. Enter your business details, request review and choose a plan in the billing portal.

One completed validation counts even if it finds invoice errors; one successful generation counts once. Unfinished work reserves allowance. Downloads and idempotent replays add no usage. Malformed requests and service failures do not use allowance. The cap stops new account operations until capacity is available, your period renews or you upgrade; there are no automatic overage charges.

The anonymous validators and JSON playground remain free with request and rate limits. Anonymous use has no saved history or account allowance. Ironfang Finance subscriptions, payment details and invoice history are separate from Ironfang Render and Ironfang Audit.

Request limits

XML and generation JSON are limited to 5 MiB, and an XML validation has a 10-second deadline. A hybrid PDF has its own, larger limits and a longer deadline, in the ZUGFeRD / Factur-X guide. A result returns at most 1,000 inline findings: inspect the finding counts and truncation indicators, because a shortened list is not a complete audit. Rate limits return HTTP 429; respect Retry-After when it is given. The OpenAPI contracts have the input and field limits.

Machine interfaces

InterfaceDetails
Product pagehttps://ironfang.com/finance
Documentationhttps://ironfang.com/docs/finance
API base URLhttps://api.ironfang.com/finance
OpenAPI contracthttps://api.ironfang.com/finance/openapi.yaml. The same contract is served as JSON at https://api.ironfang.com/finance/openapi.json.
AuthenticationPlatform API key as a bearer token
Errorshttps://ironfang.com/problems. RFC 9457 problems; every code has its own page, and its URL is the type of the problem.
MCPReference tools only. Reference only: what a validation rule means and how to fix it, and which rulesets the validator runs. Validating and generating documents, results and jobs are REST-only; the Ironfang Finance API takes a platform API key and has no OAuth delegation yet. Tools are named finance.*. MCP server reference; every tool and schema without a token at /.well-known/ironfang-mcp.json
Discovery/apis.json, /.well-known/api-catalog and /llms.txt

Launched as Financewolf. That name survives only in compatibility identifiers: the API path alias https://api.ironfang.com/financewolf, the scope prefix financewolf: and the identifiers below keep working and are aliases of the current names.

  • schema identifiers financewolf/einvoice/.../v1 in API payloads
  • canonicalisation identifiers financewolf-json/1 and financewolf-ubl/...
  • the product value financewolf-einvoicing in signed reports
  • HTTP headers X-Financewolf-* and webhook headers Financewolf-Signature, Financewolf-Timestamp and Financewolf-Event-Id
  • packages @ironfang/financewolf (npm) and ironfang-financewolf (PyPI)
  • repository ironfang-ltd/financewolf-integrations

What a valid result does not establish

  • It does not transmit the invoice through the Peppol network.
  • It does not make Ironfang a Peppol Access Point.
  • It does not register a Peppol participant or prove its registration.
  • It does not certify legal or tax compliance.
  • It does not guarantee that a recipient will accept, book or pay the invoice.

A valid result means that these bytes passed the selected supported ruleset. Recipient requirements, business context and legal or tax questions need separate review.