Check e-invoices against selected EN 16931, XRechnung, Peppol and Factur-X rules by REST API, with returned findings explained. Free within daily limits.
This capability is in beta: it works and is tested, and we may still change details.
On this page
The Klarbon e-invoice validation API checks UBL, CII, XRechnung, Peppol BIS, Factur-X and ZUGFeRD invoices against the applicable published rules with one REST call. It picks the rule set from the file, or takes the one you name, and returns findings from the selected checks with rule ids, severities and guidance. Files are processed for the request, without a document archive.
What the API does
POST /api/v1/check takes the XML or the hybrid PDF; ruleset=auto is the default.
country selects the available country rule set when you know where the invoice goes; it does not test every recipient-specific requirement.
E-invoice write routes return validation results as well; review the returned findings before using the file.
What it does not do
A valid result means the file passed the selected checks. It does not mean the recipient will accept it, and it is not tax or legal advice. Validation is in beta. Checks are free within your plan's daily checks; to change a supported file to another format, use the e-invoice conversion API.
Quick start
Each snippet is the same call. The end-to-end test runs these snippets against a local Klarbon server and the real validation engine.
Create a key on your account page and put it in KLARBON_API_KEY. Never put it in the address.
using System.Net.Http.Headers;
using System.Text.Json;
using var http = new HttpClient();
var key = Environment.GetEnvironmentVariable("KLARBON_API_KEY");
http.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", key);
var upload = new ByteArrayContent(await File.ReadAllBytesAsync("invoice.xml"));
upload.Headers.ContentType = new MediaTypeHeaderValue("application/xml");
using var request = new HttpRequestMessage(HttpMethod.Post, "https://klarbon.app/api/v1/check") { Content = upload };
using var response = await http.SendAsync(request);
using var json = JsonDocument.Parse(await response.Content.ReadAsStringAsync());
var result = json.RootElement;
if (!result.GetProperty("ok").GetBoolean())
{
Console.Error.WriteLine($"{(int)response.StatusCode} {result.GetProperty("error")}: {result.GetProperty("message")}");
return 1;
}
var report = result.GetProperty("report");
Console.WriteLine(report.GetProperty("valid").GetBoolean() ? "valid" : "not valid");
foreach (var finding in report.GetProperty("findings").EnumerateArray())
Console.WriteLine($"{finding.GetProperty("severity")} {finding.GetProperty("ruleId")} {finding.GetProperty("message")}");
return 0;
What comes back
The answer to the curl call above, recorded from that run with KoSIT XRechnung test suite, business case 01.01a (UBL), Apache-2.0.
Prepaid API packs, bought by card on your account page: 1,000 calls for €39.00, 5,000 calls for €129.00, 25,000 calls for €449.00, 100,000 calls for €990.00, VAT included, never expiring. Your first key brings 25 free calls once per email address, excluding disposable addresses. Paid calls spend the API balance first, then the same credits as the site. A call that fails costs nothing.
Call
Cost
POST /open
Free, fair use 1,000 a day per account
POST /check
Free within your plan's daily checks (20 a day on the free plan)
POST /convert, POST /make
1 call, only when the written file validates
POST /bank/convert
1 call per started 500 transactions, only when converted
Limits
Files up to 20 MB, PDFs up to 50 pages.
60 requests a minute per key, 120 per account. A per-minute rate-limit refusal carries Retry-After.
Up to 10 keys per account. Idempotency-Key is honoured for 24 hours, so a retry never charges twice.
Errors
Every error is { ok: false, error, message }: a stable code and one plain sentence.
Status
Code
When
401
auth
No key, or an unknown or revoked key.
402
no_credits
The combined API balance and credits cannot cover this call. Nothing was charged; topUpUrl says where to buy.
413
too_large
Over 20 MB or 50 PDF pages.
415
unsupported
A file format the route does not take.
422
invalid
The file could not be read, or the written file did not validate. Not charged.
429
limit
A rate limit or the day's free calls.
503
engine_unavailable
Validation is briefly unavailable. Not charged.
Privacy
Files are processed for the request, without a document archive. Klarbon's application logs carry no file name, no content and no key. The full key is not stored, only an HMAC of it and a short display prefix.
EN 16931 in UBL and CII, XRechnung, Peppol BIS Billing, Factur-X and ZUGFeRD profiles, NLCIUS and the French CTC rules. GET /api/v1/formats lists what is available.
How does the API choose the rule set?
From the file’s customisation id and container, unless you pass ruleset or country. The report names the rule set it used.
What is the difference between fatal, warning and information?
A fatal finding means the file failed a rule in the selected check. Warnings and information do not fail that check, but may still matter to the recipient.
Does a valid result mean my customer will accept the invoice?
No. It means the file passed the selected checks. Recipients and platforms can add their own requirements.