API — €49/mo

E-invoice validation API

POST an XML invoice, receive a structured JSON validation report. Supports XRechnung, Factur-X, ZUGFeRD, Peppol BIS 3.0, UBL 2.1, and UN/CEFACT CII. No data is stored or logged.

Authentication

All requests require an API key passed in the X-Api-Key header. Retrieve your key from the account dashboard after subscribing.

X-Api-Key: bi_live_xxxxxxxxxxxxxxxxxxxxxxxx

Keep your API key secret — treat it like a password. Do not expose it in client-side code or public repositories.

Endpoint

POSThttps://baseinvoice.eu/api/v1/validate

Single endpoint. Accepts one invoice per request. Returns immediately — no polling required.

Request

Option A — multipart/form-data

Send the XML file as a file field. Recommended for most integrations.

POST /api/v1/validate
Content-Type: multipart/form-data
X-Api-Key: bi_live_...

file=<your-invoice.xml>

Option B — raw XML body

Send the XML directly as the request body.

POST /api/v1/validate
Content-Type: application/xml
X-Api-Key: bi_live_...

<?xml version="1.0" encoding="UTF-8"?>
<Invoice xmlns="urn:oasis:names:specification:ubl:schema:xsd:Invoice-2">
  ...
</Invoice>

PDF files are not accepted. For Factur-X or ZUGFeRD hybrid PDFs, extract the embedded XML first and submit that.

Response

Returns application/json with HTTP 200 for all processed invoices — including invalid ones. HTTP errors only occur for authentication failures or malformed requests.

{
  "valid": false,
  "format": "xrechnung-ubl",
  "profile": "urn:cen.eu:en16931:2017#compliant#urn:xoev-de:kosit:standard:xrechnung_3.0",
  "errorCount": 2,
  "warningCount": 1,
  "issues": [
    {
      "code": "BR-02",
      "severity": "error",
      "field": "cbc:ID",
      "message": "An Invoice shall have a Specification identifier (BT-24)."
    },
    {
      "code": "BR-DE-1",
      "severity": "error",
      "field": "cbc:CustomizationID",
      "message": "Das Element 'Specification identifier' muss angegeben werden."
    },
    {
      "code": "BR-CO-15",
      "severity": "warning",
      "field": "cac:TaxTotal",
      "message": "Tax amount may not match sum of tax category amounts."
    }
  ]
}

Response fields

validbooleantrue if errorCount is 0
formatstringDetected format: xrechnung-ubl, xrechnung-cii, facturx-cii, zugferd-cii, peppol-bis3-ubl, ubl, cii, unknown
profilestring | nullDetected customization ID / profile URN
errorCountnumberNumber of rule violations (must-fix)
warningCountnumberNumber of warnings (should-fix)
issues[].codestringEN 16931 or format-specific rule code (e.g. BR-02, BR-DE-1)
issues[].severitystring"error" or "warning"
issues[].fieldstring | nullXPath field name or element where the issue was found
issues[].messagestringPlain-language description and fix guidance

Error responses

401Missing or invalid X-Api-Key header
400Empty body or missing file field
415PDF submitted — extract XML first
503API not configured (contact support)

All error responses include a JSON body: { "error": "..." }

Code examples

cURL

curl -X POST https://baseinvoice.eu/api/v1/validate \
  -H "X-Api-Key: bi_live_..." \
  -F "file=@invoice.xml"

Python

import requests

with open("invoice.xml", "rb") as f:
    response = requests.post(
        "https://baseinvoice.eu/api/v1/validate",
        headers={"X-Api-Key": "bi_live_..."},
        files={"file": f},
    )

result = response.json()
if result["valid"]:
    print("Invoice is valid")
else:
    for issue in result["issues"]:
        print(f"[{issue['severity'].upper()}] {issue['code']}: {issue['message']}")

JavaScript / Node.js

import { readFileSync } from "fs";

const xml = readFileSync("invoice.xml");
const form = new FormData();
form.append("file", new Blob([xml], { type: "application/xml" }), "invoice.xml");

const res = await fetch("https://baseinvoice.eu/api/v1/validate", {
  method: "POST",
  headers: { "X-Api-Key": "bi_live_..." },
  body: form,
});

const result = await res.json();
console.log(result.valid, result.issues);

Rate limits & quotas

Included calls1,000 / month
Overage€0.05 per additional call
Max request size5 MB
Timeout30 seconds
ConcurrencyNo hard limit
Counter resetMonthly on billing date

Ready to integrate?

7-day free trial — card required, no charge until trial ends.

Start 7-day free trial →