Valinvo

Quickstart

Status: beta. Valinvo turns one JSON invoice into XRechnung 3.0.2 (Germany, UBL or CII), ZUGFeRD 2.5.2 / Factur-X 1.09.2 (a PDF with the invoice XML embedded), Factur-X, CII or UBL with the French rules (France) or Peppol BIS Billing 3.0.21 (Belgium and the Peppol network). Every generated invoice is checked against the official rules of its format before it is returned.

Terms: the API is for businesses only and is subject to the Terms of Use and the Data Processing Agreement. Without an API key, you accept them by sending the header X-Accept-Terms: 1.0 (the current version) with each request; requests without it are refused with 428 terms_not_accepted. API key holders accept in writing when the key is issued. Every API response links the terms in a Link: <…/terms>; rel="terms-of-service" header. The trial without an API key is for testing and evaluation: use sample data, not real invoices containing other people's personal data.

Support: never email real invoices. Send the validation result (rule IDs and field locations) or an anonymised copy with sample values to hello@bmk-hub.com, or use the contact form.

List formats

curl https://valinvo.bmk-hub.com/v1/formats

Create an invoice

Send the format and the invoice in one JSON body. Two complete examples: XRechnung (Germany) and Peppol (Belgium).

curl -X POST https://valinvo.bmk-hub.com/v1/invoices \
  -H 'X-Accept-Terms: 1.0' \
  -H 'Content-Type: application/json' \
  -d @invoice.peppol-be.example.json \
  -o invoice.xml -D -

The response is the XML file. The headers show the result of the official validation:

X-Validation-Status: valid
X-Validation-Warnings: 0
X-Rule-Set: peppol-bis-3.0.21-ubl-invoice

Add -H 'Accept: application/json' to get the XML and the full validation report in one JSON response.

With "format": "zugferd-en16931" the response is a PDF (save it with -o invoice.pdf); the official rules check the XML embedded in it. In JSON mode the PDF comes base64-encoded. An invoice without a delivery date gets one warning (PEPPOL-EN16931-R008, empty delivery element): the ZUGFeRD schema requires that element, so this warning is expected.

Free trial and API keys

Without a key you can create 2 invoices per day (per IP address) to try the API; the response headers X-Trial-Limit and X-Trial-Remaining show where you are, and after that you get 429 trial_limit_reached. Design partners get a beta key, sent as Authorization: Bearer <key>, which removes the daily limit. The validator stays free.

Without a key, send one request at a time (otherwise 429 one_request_at_a_time). Size limits for everyone: invoice JSON up to 2 MB and 2,000 lines; ZUGFeRD PDFs up to 500 lines and 5,000 characters per text field; at most 1,000 notes (100 in PDFs); numbers with at most 15 digits before and 10 after the decimal point (400 invalid_invoice); documents to validate up to 20 MB and 75,000 XML elements, about 3,000 detailed lines (413 document_too_large).

Rules of thumb

When something is wrong

You get 400 with every problem at once, each with the JSON path, the official rule and the EN 16931 business term:

{
  "code": "invalid_invoice",
  "message": "The invoice has 1 problem. Fix it and try again.",
  "problems": [{
    "path": "invoice.buyerReference",
    "message": "Peppol requires buyerReference or orderReference.",
    "rule": "PEPPOL-EN16931-R003",
    "businessTerm": "BT-10"
  }]
}

422 generated_invoice_invalid means the generated XML did not pass the official rules; validation.errors says why. Usually a field required by a national rule is missing.

Validate an existing invoice

curl -X POST https://valinvo.bmk-hub.com/v1/validate \
  -H 'X-Accept-Terms: 1.0' \
  -H 'Content-Type: application/xml' \
  --data-binary @invoice.xml
{"ruleSet": "peppol-bis-3.0.21-ubl-invoice", "valid": true, "errors": [], "warnings": []}

The rule set is detected from the document: XRechnung 3.0 (UBL Invoice, UBL CreditNote, CII), Peppol BIS Billing 3.0 (UBL Invoice, UBL CreditNote) and ZUGFeRD 2.x / Factur-X in CII (profiles MINIMUM, BASIC WL, BASIC, EN 16931 and EXTENDED, checked against the 2.5.2 rules). An invalid invoice is a normal 200 result with valid: false and the list of errors.

A ZUGFeRD / Factur-X PDF can be sent as it is. We check the invoice XML embedded in it, the PDF itself against PDF/A-3 (with veraPDF) and that the PDF's metadata names the same profile and attachment as the XML; the rule set then reads e.g. zugferd-2.5.2-en16931+pdf-a-3b. PDF/A errors have rule IDs like PDF/A-3 6.2.11.4.1-1 (ISO 19005-3 clause and test), metadata errors start with ZF-XMP:

curl -X POST https://valinvo.bmk-hub.com/v1/validate \
  -H 'X-Accept-Terms: 1.0' \
  -H 'Content-Type: application/pdf' \
  --data-binary @invoice.pdf

A PDF without an invoice attachment gets 400 no_embedded_invoice; an unreadable or password-protected one 400 invalid_pdf.

OpenAPI

The whole API as an OpenAPI 3 description: openapi.json. Import it into Postman, Insomnia or a code generator.

Quickstart · XRechnung validator · Peppol validator · ZUGFeRD / Factur-X validator · ZUGFeRD-csharp: your options · Error codes