Every API here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for apis
7 MCP tools reach this
find_apisBrowse and filter every API in the catalog.
get_api_artifactsOne API's artifacts, grouped by type.
get_openapiThe primary OpenAPI for this API.
find_similar_apisAPIs that look like this one.
apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.
resolveTurn a domain, URL or GitHub org into the provider it belongs to.
find_cohortsEvery scored population of providers in the catalog.
All 92 tools →
Call it yourself
curl for this page
This API
curl "https://apis.io/api/v1/apis/ironfang:ironfang-finance-v2-reports-api"
All apis
curl "https://apis.io/api/v1/apis?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we
store it to create your key and to recognise you if you sign in with another
provider. See our Privacy Policy and
Terms.
A second provider on the same verified email joins the account you already have.
openapi: 3.2.0
info:
title: Ironfang Finance E-Invoicing V2 Reports API
version: 2.0.0
summary: Validate XRechnung, ZUGFeRD / Factur-X and Peppol invoices, as XML or as a PDF with embedded XML.
description: 'V2 validates an e-invoice against the exact, immutable ruleset of its
family and reports precisely what was checked.'
contact:
name: Ironfang
email: hello@ironfang.uk
url: https://ironfang.com/finance
termsOfService: https://ironfang.com/legal/terms
license:
name: Proprietary
identifier: LicenseRef-Ironfang-Proprietary
servers:
- url: https://api.ironfang.com/finance
description: Production. Paths below are relative to this product prefix.
tags:
- name: Reports
description: Signed reports of retained results, and their verification.
paths:
/v2/einvoices/reports:
post:
tags:
- Reports
operationId: createEInvoiceReportV2
summary: Download a signed report of a retained result
description: 'A ZIP binding the exact retained result, its complete findings and
the facts it records to an Ed25519 signature by Ironfang Finance.
The report is in its result''s version. A V2 validation, XML or
hybrid PDF, gets the V2 manifest
(`ironfang/finance/einvoice/report-manifest/v2`): the input and, for
a PDF, its embedded XML by hash; the ruleset release with its
family, variant, syntax, scope and manifest checksum (see the
ruleset''s `manifest_sha256`); for
a hybrid release the PDF engine, PDF/A profiles and binding table it
pins; both engines by image digest; every check group and layer;
what was not checked; and the release''s rule artefacts by hash. A
result made through V1 gets exactly the bundle
`POST /finance/v1/einvoices/reports` issues, V1 manifest and all.
The ZIP holds `manifest.json` (canonical), `signature.json`,
`result.json` (the retained bytes), `findings.json` and a readable
`report.html` derived from the manifest; with RFC 3161 timestamps
configured, `timestamp.tsq` and `timestamp.tsr` too. V2 reports
sign under their own domain and envelope schema, so a V1 signature
can never be read as V2 or the reverse. Both are signed by the keys
at `GET /finance/v1/einvoices/reports/keys`.
Send `operation_id` (and, for a V1 generation only, `include_pdf`)
in a JSON body of at most 1024 bytes. A V2 result has no readable
PDF: `include_pdf` on one is `503 report_unavailable`. Truncated
findings are `422 report_incomplete`. Nothing is validated or
charged again and nothing is stored; issuance time and signature may
differ between downloads of one result, its facts never do. Expiry
and deletion are checked again before the bundle is released.
A signature does not certify compliance.'
security:
- platformKey: []
x-ironfang-scopes:
- finance:einvoices:read
requestBody:
required: true
content:
application/json:
schema:
$ref: '#/components/schemas/ReportRequest'
responses:
'200':
description: The signed report ZIP as an attachment. Cache-Control is no-store.
content:
application/zip:
schema:
type: string
format: binary
'400':
$ref: '#/components/responses/MalformedRequest'
'401':
$ref: '#/components/responses/Unauthenticated'
'403':
$ref: '#/components/responses/InsufficientScope'
'404':
$ref: '#/components/responses/NotFound'
'410':
$ref: '#/components/responses/ResultGone'
'415':
$ref: '#/components/responses/UnsupportedContentType'
'422':
$ref: '#/components/responses/ReportIncomplete'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
'503':
$ref: '#/components/responses/ReportUnavailable'
/v2/einvoices/reports/verify:
post:
tags:
- Reports
operationId: verifyEInvoiceReportV2
summary: Verify a signed report of either version, without an account
description: 'Send the ZIP as `application/zip`. Ironfang Finance reads which
manifest it carries (V1''s or V2''s) and checks the canonical
manifest, the domain-separated signature against its own published
keys, every bound member''s hash and length, the readable page and,
where the report requires one, its RFC 3161 timestamp. It performs
no network access, no validation and no retention. HTTP 200 answers
`verified` true or false; verified means the report is intact and
issued by a trusted key, not that the invoice is valid: read
`invoice_outcome`. `report_schema` names the manifest; `family` and
`scope` are the release''s (a V1 report is Peppol BIS Billing 3 at
XML scope). Unknown or revoked keys, tampering and unknown schemas
fail. For a completely local check, `ironfang finance verify` does
the same with keys you obtain independently.
Bounded to 48 MiB compressed and expanded, nine members, two checks
at a time per API process and 15 seconds. No query, compression or
Idempotency-Key. Per-address anonymous limits apply.'
security:
- {}
requestBody:
required: true
content:
application/zip:
schema:
type: string
format: binary
responses:
'200':
description: The integrity check. Cache-Control is no-store.
content:
application/json:
schema:
$ref: '#/components/schemas/ReportVerification'
examples:
verified:
summary: A verified V2 report of a hybrid ZUGFeRD PDF
externalValue: https://api.ironfang.com/finance/v2/examples/v2-report-verification.json
tampered:
summary: A report whose findings were changed after signing
externalValue: https://api.ironfang.com/finance/v2/examples/v2-report-verification-failed.json
'400':
$ref: '#/components/responses/MalformedRequest'
'413':
$ref: '#/components/responses/PayloadTooLarge'
'415':
$ref: '#/components/responses/UnsupportedContentType'
'429':
$ref: '#/components/responses/RateLimited'
'500':
$ref: '#/components/responses/InternalError'
components:
schemas:
BillingRefusal:
type: object
description: 'On a billing refusal only: the product and meter the unified billing account refused, and when the free allowance renews (the start of the next UTC month) where that is the reason.'
additionalProperties: false
properties:
product:
type: string
enum:
- finance
meter:
type: string
enum:
- finance.validation
- finance.generation
reset_at:
type: string
format: date-time
Family:
type: string
description: 'An invoice family. `zugferd-facturx` is one family: ZUGFeRD and Factur-X are corresponding release names of the same standard.'
enum:
- peppol-bis-billing-3
- xrechnung
- zugferd-facturx
RequestID:
type: string
pattern: ^[A-Za-z0-9_-]{8,64}$
Declared:
type: object
description: 'What the document itself declares, copied from its source identifiers. A declaration, not a verdict: validation decides whether it is true.'
additionalProperties: false
required:
- syntax
properties:
syntax:
type: string
description: The syntax the root element names.
enum:
- ubl
- cii
- other
root:
type: string
description: The root element's local name.
maxLength: 64
specification_id:
type: string
description: UBL CustomizationID, or CII GuidelineSpecifiedDocumentContextParameter/ID.
maxLength: 256
business_process_id:
type: string
description: UBL ProfileID, or CII BusinessProcessSpecifiedDocumentContextParameter/ID.
maxLength: 256
type_code:
type: string
description: The invoice type code, which decides invoice or credit note in CII.
maxLength: 8
family:
$ref: '#/components/schemas/Family'
variant:
$ref: '#/components/schemas/Variant'
pdf:
type: object
description: For a PDF, the invoice declarations in its XMP metadata.
additionalProperties: false
properties:
conformance_level:
type: string
maxLength: 32
document_file_name:
type: string
maxLength: 128
document_type:
type: string
maxLength: 32
version:
type: string
maxLength: 16
pdfa_part:
type: string
maxLength: 4
pdfa_conformance:
type: string
maxLength: 4
Variant:
type: string
description: 'A variant or profile within a family. XRechnung: `core`, `extension`, `cvd`. ZUGFeRD / Factur-X: `minimum`, `basic-wl`, `basic`, `en16931`, `extended`, `xrechnung` (the ZUGFeRD XRECHNUNG reference profile). Peppol BIS Billing 3 has none. Recognition is not support: the ruleset list is the only statement of what is validated.'
enum:
- core
- extension
- cvd
- minimum
- basic-wl
- basic
- en16931
- extended
- xrechnung
OpaqueID:
type: string
pattern: ^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$
RulesetID:
type: string
pattern: ^fwrs_[a-z0-9_]{1,80}$
ReportRequest:
type: object
additionalProperties: false
required:
- operation_id
properties:
operation_id:
$ref: '#/components/schemas/OpaqueID'
include_pdf:
type: boolean
description: A readable PDF of a retained V1 generation. A V2 result has none.
ReportVerification:
type: object
additionalProperties: false
description: 'The integrity check of a signed report of either version. A
verified report passed every stage and says what it records; an
unverified one gives at least one reason in `errors` and records
nothing.
'
required:
- schema
- verified
- signature
- artifact_hashes
- timestamp
- errors
- claim
properties:
schema:
type: string
const: ironfang/finance/einvoice/report-verification/v2
verified:
type: boolean
report_schema:
type: string
enum:
- financewolf/einvoice/report-manifest/v1
- ironfang/finance/einvoice/report-manifest/v2
signature:
type: string
enum:
- not_verified
- verified
- invalid
- untrusted
artifact_hashes:
type: string
enum:
- not_verified
- verified
- invalid
timestamp:
type: string
enum:
- not_present
- not_verified
- verified
- invalid
manifest_sha256:
$ref: '#/components/schemas/SHA256'
operation_id:
$ref: '#/components/schemas/OpaqueID'
invoice_outcome:
type: string
enum:
- valid
- invalid
ruleset_id:
$ref: '#/components/schemas/RulesetID'
family:
$ref: '#/components/schemas/Family'
scope:
$ref: '#/components/schemas/Scope'
key_id:
type: string
pattern: ^fw_ed25519_[0-9a-f]{64}$
errors:
type: array
maxItems: 8
items:
type: string
maxLength: 256
claim:
type: string
maxLength: 1024
Problem:
type: object
description: 'An RFC 9457 problem. `code` is the stable identifier and fixes `status` and `type`. `detail` is safe to show: it never carries parser output, invoice content or stack traces.'
additionalProperties: false
required:
- type
- title
- status
- detail
- code
- request_id
properties:
type:
type: string
format: uri
pattern: ^https://ironfang\.com/problems/[a-z_]+$
title:
type: string
minLength: 1
maxLength: 128
status:
type: integer
minimum: 400
maximum: 599
detail:
type: string
minLength: 1
maxLength: 512
instance:
type: string
format: uri-reference
maxLength: 256
code:
type: string
enum:
- malformed_request
- unauthenticated
- insufficient_scope
- not_found
- idempotency_conflict
- ruleset_disabled
- result_gone
- payload_too_large
- unsupported_content_type
- unknown_ruleset
- selection_conflict
- family_undetected
- family_mismatch
- unsupported_variant
- unsupported_document_type
- scope_unavailable
- no_embedded_invoice
- ambiguous_embedded_invoice
- encrypted_pdf
- processing_limit
- rate_limited
- quota_exhausted
- internal_error
- validator_unavailable
- validation_timeout
- delivery_unavailable
- jobs_unavailable
- report_incomplete
- report_unavailable
- free_allowance_exhausted
- account_budget_exhausted
- product_budget_exhausted
- exemption_limit_reached
- paid_usage_paused
- payment_required
- payment_action_required
- account_restricted
- account_closed
- product_not_eligible
- billing_temporarily_unavailable
request_id:
$ref: '#/components/schemas/RequestID'
errors:
type: array
description: Field-level errors, on `malformed_request` only.
minItems: 1
maxItems: 50
items:
$ref: '#/components/schemas/FieldError'
detected:
$ref: '#/components/schemas/Declared'
description: 'On `family_mismatch`, `family_undetected` and `unsupported_variant` only: what the document declares, so a client can point to the right tool. Identifiers only, never invoice content.'
operation_id:
$ref: '#/components/schemas/OpaqueID'
description: On an indeterminate validation only, the operation that was opened.
outcome:
type: string
const: indeterminate
usage_charged:
type: boolean
const: false
retry_after_seconds:
type: integer
minimum: 1
maximum: 3600
billing:
$ref: '#/components/schemas/BillingRefusal'
allOf:
- if:
properties:
code:
const: malformed_request
then:
properties:
status:
const: 400
type:
const: https://ironfang.com/problems/malformed_request
- if:
properties:
code:
const: unauthenticated
then:
properties:
status:
const: 401
type:
const: https://ironfang.com/problems/unauthenticated
- if:
properties:
code:
const: insufficient_scope
then:
properties:
status:
const: 403
type:
const: https://ironfang.com/problems/insufficient_scope
- if:
properties:
code:
const: not_found
then:
properties:
status:
const: 404
type:
const: https://ironfang.com/problems/not_found
- if:
properties:
code:
const: idempotency_conflict
then:
properties:
status:
const: 409
type:
const: https://ironfang.com/problems/idempotency_conflict
- if:
properties:
code:
const: ruleset_disabled
then:
properties:
status:
const: 410
type:
const: https://ironfang.com/problems/ruleset_disabled
- if:
properties:
code:
const: result_gone
then:
properties:
status:
const: 410
type:
const: https://ironfang.com/problems/result_gone
- if:
properties:
code:
const: payload_too_large
then:
properties:
status:
const: 413
type:
const: https://ironfang.com/problems/payload_too_large
- if:
properties:
code:
const: unsupported_content_type
then:
properties:
status:
const: 415
type:
const: https://ironfang.com/problems/unsupported_content_type
- if:
properties:
code:
const: unknown_ruleset
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/unknown_ruleset
- if:
properties:
code:
const: selection_conflict
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/selection_conflict
- if:
properties:
code:
const: family_undetected
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/family_undetected
- if:
properties:
code:
const: family_mismatch
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/family_mismatch
- if:
properties:
code:
const: unsupported_variant
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/unsupported_variant
- if:
properties:
code:
const: unsupported_document_type
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/unsupported_document_type
- if:
properties:
code:
const: scope_unavailable
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/scope_unavailable
- if:
properties:
code:
const: no_embedded_invoice
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/no_embedded_invoice
- if:
properties:
code:
const: ambiguous_embedded_invoice
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/ambiguous_embedded_invoice
- if:
properties:
code:
const: encrypted_pdf
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/encrypted_pdf
- if:
properties:
code:
const: processing_limit
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/processing_limit
- if:
properties:
code:
const: rate_limited
then:
properties:
status:
const: 429
type:
const: https://ironfang.com/problems/rate_limited
- if:
properties:
code:
const: quota_exhausted
then:
properties:
status:
const: 429
type:
const: https://ironfang.com/problems/quota_exhausted
- if:
properties:
code:
const: internal_error
then:
properties:
status:
const: 500
type:
const: https://ironfang.com/problems/internal_error
- if:
properties:
code:
const: validator_unavailable
then:
properties:
status:
const: 503
type:
const: https://ironfang.com/problems/validator_unavailable
- if:
properties:
code:
const: delivery_unavailable
then:
properties:
status:
const: 503
type:
const: https://ironfang.com/problems/delivery_unavailable
- if:
properties:
code:
const: jobs_unavailable
then:
properties:
status:
const: 503
type:
const: https://ironfang.com/problems/jobs_unavailable
- if:
properties:
code:
const: report_incomplete
then:
properties:
status:
const: 422
type:
const: https://ironfang.com/problems/report_incomplete
- if:
properties:
code:
const: report_unavailable
then:
properties:
status:
const: 503
type:
const: https://ironfang.com/problems/report_unavailable
- if:
properties:
code:
const: validation_timeout
then:
properties:
status:
const: 504
type:
const: https://ironfang.com/problems/validation_timeout
- if:
properties:
code:
const: free_allowance_exhausted
then:
properties:
status:
const: 429
type:
const: https://ironfang.com/problems/free_allowance_exhausted
- if:
properties:
code:
const: account_budget_exhausted
then:
properties:
status:
const: 429
type:
const: https://ironfang.com/problems/account_budget_exhausted
- if:
properties:
code:
const: product_budget_exhausted
then:
properties:
status:
const: 429
type:
const: https://ironfang.com/problems/product_budget_exhausted
- if:
properties:
code:
const: exemption_limit_reached
then:
properties:
status:
const: 429
type:
const: https://ironfang.com/problems/exemption_limit_reached
- if:
properties:
code:
const: paid_usage_paused
then:
properties:
status:
const: 402
type:
const: https://ironfang.com/problems/paid_usage_paused
- if:
properties:
code:
const: payment_required
then:
properties:
status:
const: 402
type:
const: https://ironfang.com/problems/payment_required
- if:
properties:
code:
const: payment_action_required
then:
properties:
status:
const: 402
type:
const: https://ironfang.com/problems/payment_action_required
- if:
properties:
code:
const: account_restricted
then:
properties:
status:
const: 402
type:
const: https://ironfang.com/problems/account_restricted
- if:
properties:
code:
const: account_closed
then:
properties:
status:
const: 410
type:
const: https://ironfang.com/problems/account_closed
- if:
properties:
code:
const: product_not_eligible
then:
properties:
status:
const: 403
type:
const: https://ironfang.com/problems/product_not_eligible
- if:
properties:
code:
const: billing_temporarily_unavailable
then:
properties:
status:
const: 503
type:
const: https://ironfang.com/problems/billing_temporarily_unavailable
FieldError:
type: object
additionalProperties: false
required:
- field
- code
- message
properties:
field:
type: string
minLength: 1
maxLength: 64
code:
type: string
enum:
- unknown_field
- repeated
- invalid_value
- missing
message:
type: string
minLength: 1
maxLength: 256
Scope:
type: string
enum:
- xml
- hybrid_pdf
SHA256:
type: string
pattern: ^[0-9a-f]{64}$
responses:
InternalError:
description: Ironfang Finance failed. Not a verdict on anything.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: internal_error
UnsupportedContentType:
description: The media type, encoding or content is not accepted.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: unsupported_content_type
NotFound:
description: No such release or result is visible.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: not_found
ResultGone:
description: The result expired or was erased. Its operation record remains.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: result_gone
RateLimited:
description: Too many requests.
headers:
Retry-After:
$ref: '#/components/headers/RetryAfter'
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: rate_limited
PayloadTooLarge:
description: The body is over the limit for its media type.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: payload_too_large
ReportUnavailable:
description: Signed reports are not configured, or a readable PDF was asked for a result that has none. The result is unchanged.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: report_unavailable
MalformedRequest:
description: The request is malformed.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: malformed_request
ReportIncomplete:
description: The retained findings are truncated; no complete signed report can be issued.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: report_incomplete
InsufficientScope:
description: The key lacks the scope this operation needs.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: insufficient_scope
Unauthenticated:
description: The credential is missing or not accepted.
content:
application/problem+json:
schema:
allOf:
- $ref: '#/components/schemas/Problem'
- properties:
code:
const: unauthenticated
headers:
RetryAfter:
description: Seconds to wait before retrying. Mirrors `retry_after_seconds`.
schema:
type: integer
minimum: 1
securitySchemes:
platformKey:
type: http
scheme: bearer
description: An Ironfang platform API key minted in the portal, carrying the scopes an operation lists.
externalDocs:
description: Ironfang Finance documentation
url: https://ironfang.com/docs/finance