Convert e-invoices between UBL, CII, XRechnung and Peppol BIS with one REST call. Charged only when the written file validates.
On this page
The Klarbon e-invoice conversion API moves invoices between UBL, CII, XRechnung and Peppol BIS with one REST call. It reads the source into the EN 16931 invoice model, writes the target format and validates the result before returning it, so you are charged only for a file that passes. Files are processed for the request, without a document archive.
What the API does
POST /api/v1/convert with target set to ubl, cii, xrechnung or peppol-bis-billing.
The answer carries the new file, its validation report and a credits block showing what the call spent. Paid calls use the API balance first, then plan or bought credits.
losses reports fields changed, omitted or assumed while writing the target. It does not report fields the reader could not carry from the source file; compare the result with your original.
Idempotency-Key makes retries safe: the same request within a day never charges twice.
What it does not do
It does not send invoices anywhere, and it does not read invoice PDFs that carry no structured data. Hybrid PDF output has its own page, the ZUGFeRD and Factur-X 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/convert?target=cii") { Content = upload };
request.Headers.Add("Idempotency-Key", "invoice-123456XX-cii");
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 written = result.GetProperty("file");
await File.WriteAllBytesAsync(written.GetProperty("filename").GetString()!,
Convert.FromBase64String(written.GetProperty("content").GetString()!));
Console.WriteLine($"{written.GetProperty("filename")} written, {result.GetProperty("credits").GetProperty("balance")} credits left");
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.
Shortened for the page: file.content: base64 cut
{
"ok": true,
"file": {
"content": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgi...",
"filename": "123456XX-cii.xml",
"mime": "application/xml",
"bytes": 6867
},
"report": {
"detected": {
"syntax": "cii",
"customizationId": "urn:cen.eu:en16931:2017#compliant#urn:xeinkauf.de:kosit:xrechnung_3.0",
"profile": "xrechnung",
"container": "xml"
},
"ruleset": {
"id": "xrechnung-3.0-cii",
"name": "XRechnung 3.0 (CII)",
"version": "3.0.2"
},
"valid": true,
"engineVersion": "1.0.0",
"durationMs": 8,
"findings": [
{
"ruleId": "BR-DE-TMP-32",
"severity": "info",
"message": "[BR-DE-TMP-32] Eine Rechnung sollte zur Angabe des Liefer-/Leistungsdatums entweder BT-72 \"Actual delivery date\", BG-14 \"Invoicing period\" oder in jeder Rechnungsposition BG-26 \"Invoice line period\" enthalten.",
"location": "/rsm:CrossIndustryInvoice[1]/rsm:SupplyChainTradeTransaction[1]",
"test": "ram:ApplicableHeaderTradeDelivery/ram:ActualDeliverySupplyChainEvent/ram:OccurrenceDateTime or ram:ApplicableHeaderTradeSettlement/ram:BillingSpecifiedPeriod or (every $line in ram:IncludedSupplyChainTradeLineItem satisfies $line/ram:SpecifiedLineTradeSettlement/ram:BillingSpecifiedPeriod)",
"title": "BR-DE-TMP-32",
"what": "[BR-DE-TMP-32] Eine Rechnung sollte zur Angabe des Liefer-/Leistungsdatums entweder BT-72 \"Actual delivery date\", BG-14 \"Invoicing period\" oder in jeder Rechnungsposition BG-26 \"Invoice line period\" enthalten.",
"fix": "",
"link": null,
"officialUrl": null
}
]
},
"losses": [],
"credits": {
"spent": 1,
"balance": 197,
"plan": 0,
"bought": 197
}
}
What it costs
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.
UBL, CII, XRechnung and Peppol BIS Billing, in either direction. GET /api/v1/formats lists every format with what it can be converted from and to.
What happens to data the target format cannot hold?
The losses list reports fields changed, omitted or assumed while writing the target. Fields not read from the original file are not included in that list; compare the result with the original.
Am I charged when the converted file is invalid?
No. A file that fails validation is not returned; the call answers 422 with the report and nothing is charged.
How do I retry without paying twice?
Send an Idempotency-Key header. A repeat with the same key and request within 24 hours runs the conversion again without another charge; the new file is not guaranteed to be byte-for-byte identical.