Build and check a document without sending it
- In the sandbox
In plain words
Runs the schema, the pre-checks, the serializer for the route and every official validation layer,
then returns the report and the documents it built, each with its bytes in content_base64 when it is 2 MiB or smaller. Nothing is sent and nothing is stored beyond
the request log. Use it while mapping a new client. A number past the limits (see the conventions) answers 422
before any check runs.
apiKeyAuthorizationBearer <token>Send your key as a bearer token: Authorization: Bearer <your-api-key>. Health is the only call that needs no key.
application/json- body
The dry run. Send either document (a canonical invoice) or connector with export (one ERP document),
not both. Both work on every route; on a route other than DE-XRECHNUNG the report starts with the connector's
mapping layer and the ERP totals check (pre-check). formats takes the route's own formats: Germany may list
several and gets each; another route names one (France: ubl, cii or facturx, the last checked as CII and as PDF).
invoice_ref?stringlength <= 100route?RouteThe country route. The same values as country_route in status events.
"PEPPOL""PL-KSEF""RO-EFACTURA""FR-PA""DE-XRECHNUNG"environment?string"sandbox""production"client?stringThe operator's key only. Applies that client's connector settings to an export; a client key always uses its own.
^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$document*One invoice in the canonical model. Field meanings follow the EN 16931 semantic model. Totals are not part of the model: the service computes them from the lines.
connector?stringWhich ERP the export comes from. business-central: one Business Central API v2.0 sales invoice. Another SAP object, such as an order or a draft, answers 400.
"business-central""sap-b1"export?The ERP document as the ERP returns it. Fields the mapping does not read are ignored.
mapping_version?stringA mapping version of that connector. The live one when left out; an unknown one answers 400.
^v[0-9]+$formats?array<>Which documents to produce where the route allows a choice (Germany: xrechnung-ubl,
xrechnung-cii or zugferd; France: ubl, cii or facturx). Defaults per route are set at onboarding.
On POST /invoices name at most one: it is the document that is built, checked and sent (the first in each
list above when left out). Peppol and Romania take ubl, Poland fa3. Another value, or more than one,
answers 400. Factur-X and ZUGFeRD are checked twice: the CII inside with the route's rules, then the PDF.
On the German route a document with no profile is built as an XRechnung.
erp_totals?The totals the ERP computed. The service computes its own from the lines and refuses the invoice (422, EI-TOTALS-MISMATCH, naming the ERP field) if they differ, instead of sending a document the ERP disagrees with. A connector reads these from the export itself; totals named here win over them.
The report, whether the document is valid or not.
application/json- response
mapping_version?stringThe connector mapping version used
valid*booleanroute*RouteThe country route. The same values as country_route in status events.
"PEPPOL""PL-KSEF""RO-EFACTURA""FR-PA""DE-XRECHNUNG"layers*array<>Each check in order, with its findings.
documents?array<>curl -X POST "https://example.com/validate" \ -H "Authorization: Bearer <your-api-key>" \ -H "Content-Type: application/json" \ -d '{ "invoice_ref": "CAPTURE-DE-OK-1790961440", "route": "DE-XRECHNUNG", "environment": "sandbox", "document": { "lang": "de", "country": "DE", "invoice": { "number": "CAPTURE-DE-OK-1790961440", "issue_date": "2026-09-26", "due_date": "2026-10-10", "type_code": 380, "currency": "EUR", "buyer_reference": "PO-88731", "period": { "start": "2026-09-01", "end": "2026-09-30" }, "notes": [ "Vielen Dank für Ihren Auftrag." ] }, "seller": { "name": "Nordlicht Software GmbH", "address": { "street": "Hafenstraße 12", "city": "Hamburg", "postcode": "20457", "country": "DE" }, "vat_id": "DE938296582", "tax_number": "27/123/45678", "company_id": "HRB 123456", "register": "Amtsgericht Hamburg HRB 123456", "managing_directors": "Geschäftsführer: Jana Petersen", "legal_info": "GmbH", "endpoint": { "id": "DE938296582", "scheme": "9930" }, "contact": { "name": "Jana Petersen", "email": "rechnung@nordlicht.example", "phone": "+49 40 1234567" }, "brand_color": "#1160FF", "accent_color": "#FF9021" }, "buyer": { "name": "Brauhaus Weber AG", "address": { "street": "Marienplatz 4", "city": "München", "postcode": "80331", "country": "DE" }, "vat_id": "DE965003781", "endpoint": { "id": "DE965003781", "scheme": "9930" } }, "lines": [ { "name": "E-Rechnung Einführung (Festpreis)", "description": "Mapping Business Central → EN 16931, Validierung XRechnung, Test im Peppol-Testnetz", "quantity": 1, "unit": "LS", "unit_price": 5900, "vat_category": "S", "vat_rate": 19 }, { "name": "Betreuung abgelehnter Rechnungen", "description": "Care Plus, September 2026", "quantity": 1, "unit": "MON", "unit_price": 349, "vat_category": "S", "vat_rate": 19 }, { "name": "Zusätzliche Schulung", "description": "Remote, Buchhaltungsteam", "quantity": 3, "unit": "HUR", "unit_price": 120, "vat_category": "S", "vat_rate": 19 } ], "payment": { "means_code": 58, "iban": "DE89 3704 0044 0532 0130 00", "bic": "COBADEFFXXX", "reference": "RE-2026-0143", "terms": "Zahlbar innerhalb von 14 Tagen ohne Abzug." }, "profile": "xrechnung" } }'{ "valid": true, "route": "DE-XRECHNUNG", "documents": [ { "sha256": "e21ab9d5097022bea30bfa9f9fe0a4c7ca9afdbd672b0ce2f9150461db773625", "kind": "xrechnung-ubl", "content_base64": "PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiPz4KPEludm9pY2UgeG1sbnM9InVybjpvYXNpczpuYW1lczpzcGVjaWZpY2F0aW9uOnVibDpzY2hlbWE6eHNkOkludm9pY2UtMiIgeG1sbnM6Y2FjPSJ1cm46b2FzaXM6bmFtZXM6c3BlY2lmaWNhdGlvbjp1Ymw6c2NoZW1hOnhzZDpDb21tb25BZ2dyZWdhdGVDb21wb25lbnRzLTIiIHhtbG5zOmNiYz0idXJuOm9hc2lzOm5hbWVzOnNwZWNpZmljYXRpb246dWJsOnNjaGVtYTp4c2Q6Q29tbW9uQmFzaWNDb21wb25lbnRzLTIiPjxjYmM6Q3VzdG9taXphdGlvbklEPnVybjpjZW4uZXU6ZW4xNjkzMToyMDE3I2NvbXBsaWFudCN1cm46eGVpbmthdWYuZGU6a29zaXQ6eHJlY2hudW5nXzMuMDwvY2JjOkN1c3RvbWl6YXRpb25JRD48Y2JjOlByb2ZpbGVJRD51cm46ZmRjOnBlcHBvbC5ldToyMDE3OnBvYWNjOmJpbGxpbmc6MDE6MS4wPC9jYmM6UHJvZmlsZUlEPjxjYmM6SUQ+Q0FQVFVSRS1ERS1PSy0xNzkwOTYxNDQwPC9jYmM6SUQ+PGNiYzpJc3N1ZURhdGU+MjAyNi0wOS0yNjwvY2JjOklzc3VlRGF0ZT48Y2JjOkR1ZURhdGU+MjAyNi0xMC0xMDwvY2JjOkR1ZURhdGU+PGNiYzpJbnZvaWNlVHlwZUNvZGU+MzgwPC9jYmM6SW52b2ljZVR5cGVDb2RlPjxjYmM6Tm90ZT5WaWVsZW4gRGFuayBmw7xyIElocmVuIEF1ZnRyYWcuPC9jYmM6Tm90ZT48Y2JjOkRvY3VtZW50Q3VycmVuY3lDb2RlPkVVUjwvY2JjOkRvY3VtZW50Q3VycmVuY3lDb2RlPjxjYmM6QnV5ZXJSZWZlcmVuY2U+UE8tODg3MzE8L2NiYzpCdXllclJlZmVyZW5jZT48Y2FjOkludm9pY2VQZXJpb2Q+PGNiYzpTdGFydERhdGU+MjAyNi0wOS0wMTwvY2JjOlN0YXJ0RGF0ZT48Y2JjOkVuZERhdGU+MjAyNi0wOS0zMDwvY2JjOkVuZERhdGU+PC9jYWM6SW52b2ljZVBlcmlvZD48Y2FjOkFjY291bnRpbmdTdXBwbGllclBhcnR5PjxjYWM6UGFydHk+PGNiYzpFbmRwb2ludElEIHNjaGVtZUlEPSI5OTMwIj5ERTkzODI5NjU4MjwvY2JjOkVuZHBvaW50SUQ+PGNhYzpQb3N0YWxBZGRyZXNzPjxjYmM6U3RyZWV0TmFtZT5IYWZlbnN0cmHDn2UgMTI8L2NiYzpTdHJlZXROYW1lPjxjYmM6Q2l0eU5hbWU+SGFtYnVyZzwvY2JjOkNpdHlOYW1lPjxjYmM6UG9zdGFsWm9uZT4yMDQ1NzwvY2JjOlBvc3RhbFpvbmU+PGNhYzpDb3VudHJ5PjxjYmM6SWRlbnRpZmljYXRpb25Db2RlPkRFPC9jYmM6SWRlbnRpZmljYXRpb25Db2RlPjwvY2FjOkNvdW50cnk+PC9jYWM6UG9zdGFsQWRkcmVzcz48Y2FjOlBhcnR5VGF4U2NoZW1lPjxjYmM6Q29tcGFueUlEPkRFOTM4Mjk2NTgyPC9jYmM6Q29tcGFueUlEPjxjYWM6VGF4U2NoZW1lPjxjYmM6SUQ+VkFUPC9jYmM6SUQ+PC9jYWM6VGF4U2NoZW1lPjwvY2FjOlBhcnR5VGF4U2NoZW1lPjxjYWM6UGFydHlMZWdhbEVudGl0eT48Y2JjOlJlZ2lzdHJhdGlvbk5hbWU+Tm9yZGxpY2h0IFNvZnR3YXJlIEdtYkg8L2NiYzpSZWdpc3RyYXRpb25OYW1lPjxjYmM6Q29tcGFueUlEPkhSQiAxMjM0NTY8L2NiYzpDb21wYW55SUQ+PGNiYzpDb21wYW55TGVnYWxGb3JtPkdtYkg8L2NiYzpDb21wYW55TGVnYWxGb3JtPjwvY2FjOlBhcnR5TGVnYWxFbnRpdHk+PGNhYzpDb250YWN0PjxjYmM6TmFtZT5KYW5hIFBldGVyc2VuPC9jYmM6TmFtZT48Y2JjOlRlbGVwaG9uZT4rNDkgNDAgMTIzNDU2NzwvY2JjOlRlbGVwaG9uZT48Y2JjOkVsZWN0cm9uaWNNYWlsPnJlY2hudW5nQG5vcmRsaWNodC5leGFtcGxlPC9jYmM6RWxlY3Ryb25pY01haWw+PC9jYWM6Q29udGFjdD48L2NhYzpQYXJ0eT48L2NhYzpBY2NvdW50aW5nU3VwcGxpZXJQYXJ0eT48Y2FjOkFjY291bnRpbmdDdXN0b21lclBhcnR5PjxjYWM6UGFydHk+PGNiYzpFbmRwb2ludElEIHNjaGVtZUlEPSI5OTMwIj5ERTk2NTAwMzc4MTwvY2JjOkVuZHBvaW50SUQ+PGNhYzpQb3N0YWxBZGRyZXNzPjxjYmM6U3RyZWV0TmFtZT5NYXJpZW5wbGF0eiA0PC9jYmM6U3RyZWV0TmFtZT48Y2JjOkNpdHlOYW1lPk3DvG5jaGVuPC9jYmM6Q2l0eU5hbWU+PGNiYzpQb3N0YWxab25lPjgwMzMxPC9jYmM6UG9zdGFsWm9uZT48Y2FjOkNvdW50cnk+PGNiYzpJZGVudGlmaWNhdGlvbkNvZGU+REU8L2NiYzpJZGVudGlmaWNhdGlvbkNvZGU+PC9jYWM6Q291bnRyeT48L2NhYzpQb3N0YWxBZGRyZXNzPjxjYWM6UGFydHlUYXhTY2hlbWU+PGNiYzpDb21wYW55SUQ+REU5NjUwMDM3ODE8L2NiYzpDb21wYW55SUQ+PGNhYzpUYXhTY2hlbWU+PGNiYzpJRD5WQVQ8L2NiYzpJRD48L2NhYzpUYXhTY2hlbWU+PC9jYWM6UGFydHlUYXhTY2hlbWU+PGNhYzpQYXJ0eUxlZ2FsRW50aXR5PjxjYmM6UmVnaXN0cmF0aW9uTmFtZT5CcmF1aGF1cyBXZWJlciBBRzwvY2JjOlJlZ2lzdHJhdGlvbk5hbWU+PC9jYWM6UGFydHlMZWdhbEVudGl0eT48L2NhYzpQYXJ0eT48L2NhYzpBY2NvdW50aW5nQ3VzdG9tZXJQYXJ0eT48Y2FjOlBheW1lbnRNZWFucz48Y2JjOlBheW1lbnRNZWFuc0NvZGU+NTg8L2NiYzpQYXltZW50TWVhbnNDb2RlPjxjYmM6UGF5bWVudElEPlJFLTIwMjYtMDE0MzwvY2JjOlBheW1lbnRJRD48Y2FjOlBheWVlRmluYW5jaWFsQWNjb3VudD48Y2JjOklEPkRFODkzNzA0MDA0NDA1MzIwMTMwMDA8L2NiYzpJRD48Y2JjOk5hbWU+Tm9yZGxpY2h0IFNvZnR3YXJlIEdtYkg8L2NiYzpOYW1lPjxjYWM6RmluYW5jaWFsSW5zdGl0dXRpb25CcmFuY2g+PGNiYzpJRD5DT0JBREVGRlhYWDwvY2JjOklEPjwvY2FjOkZpbmFuY2lhbEluc3RpdHV0aW9uQnJhbmNoPjwvY2FjOlBheWVlRmluYW5jaWFsQWNjb3VudD48L2NhYzpQYXltZW50TWVhbnM+PGNhYzpQYXltZW50VGVybXM+PGNiYzpOb3RlPlphaGxiYXIgaW5uZXJoYWxiIHZvbiAxNCBUYWdlbiBvaG5lIEFienVnLjwvY2JjOk5vdGU+PC9jYWM6UGF5bWVudFRlcm1zPjxjYWM6VGF4VG90YWw+PGNiYzpUYXhBbW91bnQgY3VycmVuY3lJRD0iRVVSIj4xMjU1LjcxPC9jYmM6VGF4QW1vdW50PjxjYWM6VGF4U3VidG90YWw+PGNiYzpUYXhhYmxlQW1vdW50IGN1cnJlbmN5SUQ9IkVVUiI+NjYwOS4wMDwvY2JjOlRheGFibGVBbW91bnQ+PGNiYzpUYXhBbW91bnQgY3VycmVuY3lJRD0iRVVSIj4xMjU1LjcxPC9jYmM6VGF4QW1vdW50PjxjYWM6VGF4Q2F0ZWdvcnk+PGNiYzpJRD5TPC9jYmM6SUQ+PGNiYzpQZXJjZW50PjE5LjAwPC9jYmM6UGVyY2VudD48Y2FjOlRheFNjaGVtZT48Y2JjOklEPlZBVDwvY2JjOklEPjwvY2FjOlRheFNjaGVtZT48L2NhYzpUYXhDYXRlZ29yeT48L2NhYzpUYXhTdWJ0b3RhbD48L2NhYzpUYXhUb3RhbD48Y2FjOkxlZ2FsTW9uZXRhcnlUb3RhbD48Y2JjOkxpbmVFeHRlbnNpb25BbW91bnQgY3VycmVuY3lJRD0iRVVSIj42NjA5LjAwPC9jYmM6TGluZUV4dGVuc2lvbkFtb3VudD48Y2JjOlRheEV4Y2x1c2l2ZUFtb3VudCBjdXJyZW5jeUlEPSJFVVIiPjY2MDkuMDA8L2NiYzpUYXhFeGNsdXNpdmVBbW91bnQ+PGNiYzpUYXhJbmNsdXNpdmVBbW91bnQgY3VycmVuY3lJRD0iRVVSIj43ODY0LjcxPC9jYmM6VGF4SW5jbHVzaXZlQW1vdW50PjxjYmM6UGF5YWJsZUFtb3VudCBjdXJyZW5jeUlEPSJFVVIiPjc4NjQuNzE8L2NiYzpQYXlhYmxlQW1vdW50PjwvY2FjOkxlZ2FsTW9uZXRhcnlUb3RhbD48Y2FjOkludm9pY2VMaW5lPjxjYmM6SUQ+MTwvY2JjOklEPjxjYmM6SW52b2ljZWRRdWFudGl0eSB1bml0Q29kZT0iTFMiPjE8L2NiYzpJbnZvaWNlZFF1YW50aXR5PjxjYmM6TGluZUV4dGVuc2lvbkFtb3VudCBjdXJyZW5jeUlEPSJFVVIiPjU5MDAuMDA8L2NiYzpMaW5lRXh0ZW5zaW9uQW1vdW50PjxjYWM6SXRlbT48Y2JjOkRlc2NyaXB0aW9uPk1hcHBpbmcgQnVzaW5lc3MgQ2VudHJhbCDihpIgRU4gMTY5MzEsIFZhbGlkaWVydW5nIFhSZWNobnVuZywgVGVzdCBpbSBQZXBwb2wtVGVzdG5ldHo8L2NiYzpEZXNjcmlwdGlvbj48Y2JjOk5hbWU+RS1SZWNobnVuZyBFaW5mw7xocnVuZyAoRmVzdHByZWlzKTwvY2JjOk5hbWU+PGNhYzpDbGFzc2lmaWVkVGF4Q2F0ZWdvcnk+PGNiYzpJRD5TPC9jYmM6SUQ+PGNiYzpQZXJjZW50PjE5LjAwPC9jYmM6UGVyY2VudD48Y2FjOlRheFNjaGVtZT48Y2JjOklEPlZBVDwvY2JjOklEPjwvY2FjOlRheFNjaGVtZT48L2NhYzpDbGFzc2lmaWVkVGF4Q2F0ZWdvcnk+PC9jYWM6SXRlbT48Y2FjOlByaWNlPjxjYmM6UHJpY2VBbW91bnQgY3VycmVuY3lJRD0iRVVSIj41OTAwLjAwPC9jYmM6UHJpY2VBbW91bnQ+PC9jYWM6UHJpY2U+PC9jYWM6SW52b2ljZUxpbmU+PGNhYzpJbnZvaWNlTGluZT48Y2JjOklEPjI8L2NiYzpJRD48Y2JjOkludm9pY2VkUXVhbnRpdHkgdW5pdENvZGU9Ik1PTiI+MTwvY2JjOkludm9pY2VkUXVhbnRpdHk+PGNiYzpMaW5lRXh0ZW5zaW9uQW1vdW50IGN1cnJlbmN5SUQ9IkVVUiI+MzQ5LjAwPC9jYmM6TGluZUV4dGVuc2lvbkFtb3VudD48Y2FjOkl0ZW0+PGNiYzpEZXNjcmlwdGlvbj5DYXJlIFBsdXMsIFNlcHRlbWJlciAyMDI2PC9jYmM6RGVzY3JpcHRpb24+PGNiYzpOYW1lPkJldHJldXVuZyBhYmdlbGVobnRlciBSZWNobnVuZ2VuPC9jYmM6TmFtZT48Y2FjOkNsYXNzaWZpZWRUYXhDYXRlZ29yeT48Y2JjOklEPlM8L2NiYzpJRD48Y2JjOlBlcmNlbnQ+MTkuMDA8L2NiYzpQZXJjZW50PjxjYWM6VGF4U2NoZW1lPjxjYmM6SUQ+VkFUPC9jYmM6SUQ+PC9jYWM6VGF4U2NoZW1lPjwvY2FjOkNsYXNzaWZpZWRUYXhDYXRlZ29yeT48L2NhYzpJdGVtPjxjYWM6UHJpY2U+PGNiYzpQcmljZUFtb3VudCBjdXJyZW5jeUlEPSJFVVIiPjM0OS4wMDwvY2JjOlByaWNlQW1vdW50PjwvY2FjOlByaWNlPjwvY2FjOkludm9pY2VMaW5lPjxjYWM6SW52b2ljZUxpbmU+PGNiYzpJRD4zPC9jYmM6SUQ+PGNiYzpJbnZvaWNlZFF1YW50aXR5IHVuaXRDb2RlPSJIVVIiPjM8L2NiYzpJbnZvaWNlZFF1YW50aXR5PjxjYmM6TGluZUV4dGVuc2lvbkFtb3VudCBjdXJyZW5jeUlEPSJFVVIiPjM2MC4wMDwvY2JjOkxpbmVFeHRlbnNpb25BbW91bnQ+PGNhYzpJdGVtPjxjYmM6RGVzY3JpcHRpb24+UmVtb3RlLCBCdWNoaGFsdHVuZ3N0ZWFtPC9jYmM6RGVzY3JpcHRpb24+PGNiYzpOYW1lPlp1c8OkdHpsaWNoZSBTY2h1bHVuZzwvY2JjOk5hbWU+PGNhYzpDbGFzc2lmaWVkVGF4Q2F0ZWdvcnk+PGNiYzpJRD5TPC9jYmM6SUQ+PGNiYzpQZXJjZW50PjE5LjAwPC9jYmM6UGVyY2VudD48Y2FjOlRheFNjaGVtZT48Y2JjOklEPlZBVDwvY2JjOklEPjwvY2FjOlRheFNjaGVtZT48L2NhYzpDbGFzc2lmaWVkVGF4Q2F0ZWdvcnk+PC9jYWM6SXRlbT48Y2FjOlByaWNlPjxjYmM6UHJpY2VBbW91bnQgY3VycmVuY3lJRD0iRVVSIj4xMjAuMDA8L2NiYzpQcmljZUFtb3VudD48L2NhYzpQcmljZT48L2NhYzpJbnZvaWNlTGluZT48L0ludm9pY2U+Cg==" } ], "layers": [ { "findings": [], "passed": true, "layer": "schema" }, { "findings": [], "passed": true, "layer": "mapping" }, { "findings": [], "passed": true, "layer": "pre-check" }, { "findings": [], "passed": true, "layer": "kosit" } ]}List the status events of one invoice GET
The same events the webhook delivers, in sequence order. Use it to catch up after downtime.
Get the webhook settings (the operator's, or with a client's admin key that client's own) GET
Since 0.16.0 the operator's key reads one client's settings with client. A client's admin key may name only its own client; any other answers 404. An unknown or repeated parameter, or client given empty, answers 400. Setting and testing a webhook take no query parameters at all (400): they stay with the webhook's own key.