Docs

Submit an invoice or credit note as canonical JSON

  • In the sandbox

In plain words

Submits an invoice or credit note: it is queued if it passes every check, and refused with the failing field if not.
POST
/invoices

The service checks the document against the canonical model and the pre-checks at once, and answers 422 if either fails. Everything after that runs asynchronously (build, official validation, route submission, statuses) and is reported through status events.

A corrected resubmission of a rejected invoice uses the same invoice_ref and a new Idempotency-Key; the service links the attempts.

In production an ERP export is read only when the client's connector settings hold its own seller and payment, not the mapping's example: otherwise 422 connector-settings-missing, naming what is missing. A sandbox reads it with the example, as before.

Authorization

apiKey
headerAuthorizationBearer <token>

Send your key as a bearer token: Authorization: Bearer <your-api-key>. Health is the only call that needs no key.

Header parameters

Idempotency-Key*string

A unique key per logical request (a UUID is fine). Kept for as long as the client's data is kept. With the operator's key it may not begin with client: (400), the form client keys are stored under.

Length8 <= length <= 100

Request body

application/json
  1. body

Send either document (a canonical invoice) or connector with export (one ERP document as the ERP returns it), not both (400). An export is mapped by the connector's live mapping version, or mapping_version, and then handled exactly as the canonical invoice it maps to; the export itself is kept with the invoice (erp-export). The connector's XRechnung profile applies on DE-XRECHNUNG only, and when the router chooses for a German buyer. A mapping finding (an unknown unit, a missing ERP field) answers 422 naming the ERP field.

connector?connector

Which 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.

Value in"business-central""sap-b1"
export?

The ERP document as the ERP returns it. Fields the mapping does not read are ignored.

mapping_version?mapping_version

A mapping version of that connector. The live one when left out; an unknown one answers 400.

Match^v[0-9]+$
client?string

The client the invoice belongs to. The operator's key names it (left out, the invoice belongs to the operator's own local client). A client key may leave it out or name its own client; any other client answers 403.

Match^[A-Za-z0-9][A-Za-z0-9._-]{0,63}$
invoice_ref?string

The ERP's own document ID. Echoed in every status event.

Lengthlength <= 100
route?|

Left out or null, the router chooses it from the document: the seller's country, the buyer's buyer.address.country, profile, the client's stored credentials and, when a rule needs it, the buyer's Peppol registration. When no rule fits, the answer is 422 with EI-ROUTE-UNDECIDED or EI-ROUTE-PEPPOL-UNKNOWN (source router). POST /validate still needs it.

environment?string

Must match the API key's environment; given explicitly as a guard.

Value in"sandbox""production"
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.

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.

Response body

Accepted for processing. Follow it with the returned links or wait for status events.

application/json
  1. response
id*string
state*InvoiceState

The service's own state for an invoice. Status events report the partner-facing lifecycle; queued and submitting are internal steps between validated and submitted. validation_failed means the official rules refused the document; since 0.18.4 a check that did not run (KOSIT-RUN, EI-PDF-CHECK) retries instead, then ends dead_letter with that code. A dead_letter keeps its document held, so the same file answers with duplicate_of; since 0.18.6 the operator can cancel one for which no call to the route was made, and then the file can go again.

Value in"received""source_error""validated""validation_failed""queued""submitting""submitted""ready""accepted""rejected""delivered""cancelled""dead_letter"
duplicate_of?|

Set when the same document was already accepted for this client and route; nothing new is sent. A submission that ended rejected, validation_failed or cancelled does not count, so the file can be sent again. Since 0.18.5 this holds for two requests sent at the same moment too, under different keys; one makes the invoice and the other answers with duplicate_of.

links*
route?Route

Only when the router chose the route.

Value in"PEPPOL""PL-KSEF""RO-EFACTURA""FR-PA""DE-XRECHNUNG"
route_chosen_by?"router"

Only when the request left out the route.

Value in"router"
route_rule?string

The router's rule that chose the route; also written to the audit log as route_chosen.

Value in"fr-domestic""fr-cross-border""pl-domestic""ro-domestic""be-domestic""de-domestic-peppol""de-domestic""cross-border-peppol"
curl -X POST "https://example.com/invoices" \  -H "Authorization: Bearer <your-api-key>" \  -H "Idempotency-Key: order-2026-0001" \  -H "Content-Type: application/json" \  -d '{    "invoice_ref": "CAPTURE-JSON-1790961440",    "route": "DE-XRECHNUNG",    "environment": "sandbox",    "document": {      "lang": "de",      "country": "DE",      "invoice": {        "number": "DOC-mux3dlqm",        "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": "[email protected]",          "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"    }  }'

{  "links": {    "self": "/invoices/inv_936a93e38de84e7b0a1d7681",    "events": "/invoices/inv_936a93e38de84e7b0a1d7681/events"  },  "id": "inv_936a93e38de84e7b0a1d7681",  "state": "queued"}