Skip to content

Ironfang Finance - API versions

Finance API V1 and V2

Which API validates which invoices, how requests and results differ, how history, events and jobs bring the two together, and what both share.

The Ironfang Finance API has two versions that run side by side. V1, under /finance/v1, is unchanged: its clients keep their Peppol shapes, and it never returns a V2 result. V2, under /finance/v2, validates more families and formats and reports exactly what was checked. Nothing has to move: a V1 integration keeps working, and V2 is where the other families are.

Which API serves what

WhatAPI
Peppol BIS Billing 3 validation (UBL)V1. V2 has no Peppol release yet and answers 422 unknown_ruleset.
XRechnung 3.0.2 validation (UBL or CII)V2 only (family=xrechnung).
ZUGFeRD 2.5.2 / Factur-X 1.09.2 validation (CII XML or hybrid PDF)V2 only (family=zugferd-facturx).
Invoice generation from JSONV1 only (POST /finance/v1/einvoices/generate).
Readable PDF of a generated invoiceV1 only (POST /finance/v1/einvoices/render).
Signed evidence reportsBoth. POST /finance/v2/einvoices/reports signs a report of any retained result in that result's own version, V1 or V2; V1's POST /finance/v1/einvoices/reports signs V1 results only. POST /finance/v2/einvoices/reports/verify checks reports of either version.
Retained results, deliveries, jobs and batchesBoth. V2 lists V1 and V2 records together; V1 lists only its own.
Destinations (webhooks and S3)V1 routes (/finance/v1/einvoices/destinations); one destination receives V1 and V2 events.

GET /finance/v2/einvoices/rulesets lists exactly which family, variant, syntax, document type and scope each active V2 release covers; nothing else is supported. The family guides say more: XRechnung and ZUGFeRD / Factur-X.

Requests

Both versions take the document as the request body, choosing with query parameters, or as multipart/form-data with one document part and an optional options part holding the same choices as JSON. Query parameters are not read for multipart requests, and an unknown or repeated parameter or part is 400 malformed_request in both.

V1V2
Bodyapplication/xml or text/xmlThe same, or application/pdf for a hybrid invoice. The content is inspected; XML holding a PDF, or the reverse, is 415.
Choicesruleset, profile, document_typeruleset, family, variant, document_type, scope
DetectionWithout a profile, from the document's CustomizationID and ProfileIDWithout a family, from the document's declaration. A named family the document contradicts is 422 family_mismatch, with what it declares in detected.
ScopeXML onlyxml for XML, hybrid_pdf for a PDF; any other combination is 422 scope_unavailable.
SizeXML up to 5 MiBXML up to 5 MiB; a PDF up to 20 MiB, 200 pages and 20 embedded files, with its invoice XML up to 5 MiB.
Deadline10 seconds10 seconds for XML, 30 seconds for a PDF

Results

A V1 result has the schema financewolf/einvoice/validation-result/v1, a V2 result ironfang/finance/einvoice/validation-result/v2. Both say outcome valid or invalid for a completed validation, decided by the fatal findings alone; anything that stopped a verdict is a Problem with outcome: indeterminate and nothing charged, in both. The fields that differ:

FieldV1V2
inputsha256, bytes, content_type, document_typemedia_type for content_type; for a PDF also embedded_xml, the XML that was checked
rulesetrequested, id, selection_method, state, vesid, official_releaseNo vesid; adds family, variant, syntax, scope and technical_release
profileThe profile familyNot present: ruleset.family and ruleset.variant
declaredNot presentWhat the document says about itself, copied: syntax, root, specification and process identifiers, type code, and for a PDF what its metadata declares
layersAlways the same five: input, xml, xsd, en16931, peppolThe family's own sequence from input, pdfa, hybrid_binding, xml, xsd, en16931, peppol, xrechnung and zugferd_profile
groupsNot presentThe layers grouped: invoice_xml always, and for a PDF pdfa and attachment_metadata before it
coverageNot presentThe scope, the layers that ran, and not_checked: what the result cannot establish, such as a PDF that was not supplied
engine / enginesOne engine: name, image digest, hint pack versionAn engines list, each with a role: xml, and pdf for a hybrid check
links / next_actionslinksnext_actions: view, and extract_xml for a PDF

operation_id, status, counts, findings_summary, timing and usage are in both. counts in V2 also counts information findings.

Findings

V1V2
Severityfatal or warningfatal, warning or information; rule_flag is the rule's own flag where the family's configuration sets another level
Locationlocation (a string) and location_kind: none, xpath or line-columnOne location object with kind (also pdf, a PDF object path) and value
SourceAn FW- rule id marks Ironfang's own checkrule_source: official or ironfang
Guidancehint_code, hint, source_url, ruleset_idhint_code, source_url

In both, message is one of Ironfang's fixed messages: the official rule texts are not repeated, because they can carry invoice values. rule_id is the official identifier, unchanged.

Retained results

GET /finance/v2/einvoices/results lists validations and generations made through V1 and validations made through V2 together, each saying which API made it (api_version), the schema of its retained document (result_schema) and its family, with filters on each. GET /finance/v2/einvoices/results/{id} returns any of them in the schema it was made under, and DELETE erases either. V1's own list shows only V1 results, and reading a V2 result through V1 is 404: a V2 result is not a document V1's schema describes. Results are kept for 30 days in both.

Webhook events and deliveries

A finished operation queues one event, delivered to every enabled webhook or S3 destination and signed the same way whichever API made it. An operation made through V1 sends financewolf/einvoice/event/v1, whose result_url is under /finance/v1. An operation made through V2 sends ironfang/finance/einvoice/event/v2, whose result_url is under /finance/v2 and whose data also carries the family, variant and scope the result was made under. A receiver that takes both should branch on schema.

GET /finance/v2/einvoices/deliveries lists deliveries of both kinds, each with its api_version and its event as queued, and can filter on api_version. POST /finance/v2/einvoices/deliveries/{id}/retry retries a failed one of either kind. V1's delivery list, read and retry see only deliveries of V1 events.

Jobs and batches

POST /finance/v2/einvoices/jobs queues one V2 validation and POST /finance/v2/einvoices/batches 1 to 100 together, all or none. Each job carries document_base64, its media_type and the synchronous options. A document synchronous validation would refuse is refused on acceptance with the same Problem, and nothing is queued or charged. A job's result, usage and event are exactly a synchronous validation's.

V1V2
OperationsValidation and generationValidation
DocumentXML up to 5 MiBXML up to 5 MiB or a PDF up to 20 MiB
Job envelope8 MiB28 MiB
Batch1 to 100 jobs, envelope 32 MiB1 to 100 jobs, documents 25 MiB together, envelope 36 MiB

V1 and V2 jobs share each organisation's queue: at most 100 unfinished jobs and 25 MiB of their documents, held encrypted until they finish, at most 24 hours. V1's job and batch lists show only V1 work; V2's show both.

What both share

The contracts: V1 and V2.

Example

No single document goes through both APIs today, because Peppol has no V2 release. The request mechanics are the same, so this pairs a V1 Peppol call with a V2 XRechnung call, and adds the PDF only V2 takes.

# V1: a Peppol BIS Billing 3 invoice (UBL). Peppol is validated through V1.
curl --fail-with-body --silent --show-error \
  "https://api.ironfang.uk/finance/v1/einvoices/validate?ruleset=latest&profile=peppol-bis-billing-3" \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/xml" \
  -H "Idempotency-Key: peppol-invoice-0001" \
  --data-binary @peppol-invoice.xml

# V2: an XRechnung invoice (UBL or CII). The same request mechanics,
# with the family named instead of a profile.
curl --fail-with-body --silent --show-error \
  "https://api.ironfang.uk/finance/v2/einvoices/validate?ruleset=latest&family=xrechnung" \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/xml" \
  -H "Idempotency-Key: xrechnung-invoice-0001" \
  --data-binary @xrechnung-invoice.xml

# V2: a ZUGFeRD / Factur-X hybrid PDF. Only V2 takes a PDF.
curl --fail-with-body --silent --show-error \
  "https://api.ironfang.uk/finance/v2/einvoices/validate?family=zugferd-facturx" \
  -H "Authorization: Bearer $IRONFANG_API_KEY" \
  -H "Content-Type: application/pdf" \
  --data-binary @zugferd-invoice.pdf