XRechnung validation in GitHub Actions
Keep your invoice templates valid on every push: one curl step, rule violations as annotations on the file, a red job when an invoice would be rejected.
curl -H "Authorization: Bearer $FINEKOT_KEY" -F file=@invoice.xml https://api.finekot.com/v1/e-invoice
{
"valid": false,
"verdict": "technically_invalid",
"profile": {"name": "XRechnung 3.0"},
"errors": 3, "warnings": 1,
"issues": [
{"rule": "BR-DE-15", "severity": "error",
"message": "Das Element \"Buyer reference\" (BT-10) muss übermittelt werden.",
"location": "/ubl:Invoice[1]"},
…
],
"cost": 0.02, "balance": 0.98
}No subscription, no contract.
create from JSON €0.04 · PDF → XRechnung €0.10
A subscription bills the same monthly plan for 10 invoices or 1,000. Here you prepay any amount and pay per call; unused credit stays.
10 free checks a day · €1 free with a key · then €0.02 per check
Workflow with curl and jq
Store the key as the repository secret FINEKOT_KEY. ubuntu-latest has curl and jq; no Java setup step, no validator download.
# .github/workflows/einvoice.yml
name: e-invoice
on: [push, pull_request]
jobs:
validate:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Validate XRechnung files
env:
FINEKOT_KEY: ${{ secrets.FINEKOT_KEY }}
run: |
fail=0
for f in invoices/*.xml; do
r=$(curl -sS -H "Authorization: Bearer $FINEKOT_KEY" -F file=@"$f" \
https://api.finekot.com/v1/e-invoice)
echo "$r" | jq -r --arg f "$f" '"\($f): \(.verdict), \(.errors) errors"'
echo "$r" | jq -r --arg f "$f" \
'.issues[] | select(.severity=="error") | "::error file=\($f)::[\(.rule)] \(.message)"'
[ "$(echo "$r" | jq .valid)" = "true" ] || fail=1
done
exit $failValidate an e-invoice
Official EN 16931 and XRechnung rules. Errors with rule id, message and location.
10 free checks a day · €1 free with a key · then €0.02 per check
Processed on servers in Germany (Hetzner, Falkenstein). The uploaded file is checked in memory and not stored.
The verdict, profile, totals and every rule violation appear here.
Why in CI
Invoice output breaks quietly: a refactoring drops the buyer reference, a rounding change breaks BR-CO-16. A CI check on fixture invoices catches it before a customer's inbound portal does.
Each file costs €0.02; a suite of 20 fixtures on every push is €0.40. Without a key the playground endpoint /v1/try/e-invoice allows 10 checks a day per IP.
The check uses EN 16931 1.3.17 and KoSIT XRechnung schematron 2.6.0, the schematron sets the KoSIT validator runs for XRechnung; its XSD step is not part of this check.
Price in plain numbers
A prepaid balance, no subscription. Charged only for a successful answer; errors are free.
A new key comes with €1 of free credit: 50 validations.
Credits never expire. No subscription.
Apple Pay, Google Pay or card on the monobank page. The key is created for you if you have none.
No key in this browser yet.
For developers
Same checks over REST and MCP. One header, JSON out.
curl https://api.finekot.com/v1/e-invoice \
-H "Authorization: Bearer fk_live_…" \
-F file=@invoice.xml
# → {"valid":false,"errors":2,"issues":[{"rule":"BR-DE-15",…}]}
# X-Cost: 0.02curl https://api.finekot.com/v1/e-invoice \
-H "Authorization: Bearer fk_live_…" \
-H "Content-Type: application/json" \
-d '{"op":"create","output":"pdf","invoice":{…}}'
# → Factur-X PDF url + validation report · X-Cost: 0.04claude mcp add --transport http finekot https://api.finekot.com/mcp --header "Authorization: Bearer fk_live_…"
Full reference: /llms.txt · /openapi.json · /.well-known/mcp.json