E-invoicing
XRechnung and ZUGFeRD / Factur-X: check, receive as a draft bill, issue.
| Operation | Summary | Scope | Idempotency-Key |
|---|---|---|---|
POST /v1/documents/einvoice |
Receive an e-invoice as a draft bill | draft |
required |
POST /v1/einvoices/check |
Check an e-invoice | read |
|
GET /v1/invoices/{invoice}/xrechnung |
Issue a sales invoice as XRechnung | read |
POST /v1/documents/einvoice
Receive an e-invoice as a draft bill
Turn a structured e-invoice into a draft bill (no model involved).
Send multipart/form-data: the invoice in the form field file, plus the form fields
entity (required), vendor, create_vendor and submit. The file is stored as the
bill's source document. An invoice that breaks a fatal EN 16931 or XRechnung rule is
stored but not booked (status: invalid) and the violations are listed by rule id.
The result's status is draft, pending_approval or posted (with submit=true, as
the approval policy decides; the bill of a draft vendor stays a draft with a warning),
invalid, or needs_review (unknown vendor with create_vendor=false, or a negative
total). The same file or vendor invoice number is refused with 409. With submit=true, an
invoice dated in a closed period is refused with 409 (period_closed, nothing is kept): its
hint says to import it with submit=false and give the draft bill a date in an open period
(PATCH /v1/documents/{document_id}), then submit it. A foreign vendor's VAT that cannot be
reclaimed is booked as part of the cost, so the bill's total is the invoice total; a bill
quoting a purchase order none of the vendor's waits for a second person.
| Required scope | draft (admin implies every scope) |
| Idempotency-Key | required |
| Operation id | import_einvoice_v1_documents_einvoice_post |
Request body
multipart/form-data (required): Body_import_einvoice_v1_documents_einvoice_post
| Field | Type | Required | Description |
|---|---|---|---|
entity |
string | yes | Code of the entity that receives the bill, e.g. DE01. |
file |
string | yes | The e-invoice: an XRechnung XML file (UBL or CII) or a ZUGFeRD / Factur-X PDF with the XML embedded. At most 20 MB. |
vendor |
string or null | Vendor code, e.g. V-IT; default: the vendor is found by the seller's VAT id, then by IBAN. |
|
create_vendor |
boolean | Create an unknown vendor as a draft vendor from the seller's details (true, default); false answers status needs_review instead. (default true) |
|
submit |
boolean | true: also submit the bill through the approval policy; false (default): leave it a draft. (default false) |
Example request
curl -X POST "$ERP_URL/v1/documents/einvoice" \
-H "Authorization: Bearer $ERP_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-F "file=@statement.xml" \
-F "entity=CH01"
Responses
| Status | Meaning | Body |
|---|---|---|
| 201 | Created | EInvoiceResult |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"status": "draft",
"valid": true,
"label": "string",
"profile": "string",
"syntax": "string",
"container": "string",
"violations": [
{
"rule": "string",
"severity": "fatal",
"message": "string",
"location": "string"
}
],
"warnings": [
"string"
],
"document_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"sha256": "string",
"bill_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"bill_kind": "string",
"approval_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"vendor": {
"code": "string",
"name": "string",
"matched_by": "created",
"status": "string"
},
"total": "string",
"currency": "string",
"invoice": {
"syntax": "CII",
"specification_id": "string",
"business_process": "string",
"number": "string",
"issue_date": "2026-09-21",
"type_code": "string",
"currency": "string",
"tax_currency": "string",
"tax_point_date": "2026-09-21",
"tax_point_code": "string",
"due_date": "2026-09-21",
"buyer_reference": "string",
"project_reference": "string",
"contract_reference": "string",
"order_reference": "string",
"sales_order_reference": "string",
"receiving_advice": "string",
"despatch_advice": "string",
"tender_reference": "string",
"invoiced_object": "string",
"accounting_reference": "string",
"payment_terms": "string",
"notes": [
"string"
],
"preceding_invoices": [
{
"number": null,
"issue_date": null
}
],
"seller": {
"name": null,
"trading_name": null,
"identifiers": [
null
],
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"buyer": {
"name": null,
"trading_name": null,
"identifiers": [
null
],
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"payee": {
"name": null,
"trading_name": null,
"identifiers": null,
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"tax_representative": {
"name": null,
"trading_name": null,
"identifiers": null,
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"delivery_date": "2026-09-21",
"period_start": "2026-09-21",
"period_end": "2026-09-21",
"deliver_to": {
"line1": null,
"line2": null,
"line3": null,
"city": null,
"postal_code": null,
"subdivision": null,
"country": null
},
"payment_means": [
{
"code": null,
"text": null,
"account_id": null,
"account_name": null,
"bic": null,
"card_number": null,
"card_holder": null,
"mandate_id": null,
"debited_account": null
}
],
"remittance_information": "string",
"creditor_reference_id": "string",
"allowances_charges": [
{
"charge": null,
"amount": null,
"base_amount": null,
"percent": null,
"vat_category": null,
"vat_rate": null,
"reason": null,
"reason_code": null
}
],
"totals": {
"line_total": null,
"allowance_total": null,
"charge_total": null,
"tax_exclusive": null,
"tax_total": null,
"tax_total_accounting": null,
"tax_inclusive": null,
"prepaid": null,
"rounding": null,
"payable": null,
"third_party_payments": null
},
"vat_breakdown": [
{
"taxable_amount": null,
"tax_amount": null,
"category": null,
"rate": null,
"exemption_reason": null,
"exemption_reason_code": null
}
],
"lines": [
{
"id": null,
"note": null,
"quantity": null,
"unit_code": null,
"net_amount": null,
"order_line_reference": null,
"accounting_reference": null,
"period_start": null,
"period_end": null,
"allowances_charges": null,
"net_price": null,
"price_discount": null,
"gross_price": null,
"base_quantity": null,
"vat_category": null,
"vat_rate": null,
"name": null,
"description": null,
"seller_item_id": null,
"buyer_item_id": null,
"standard_item_id": null,
"classifications": null,
"origin_country": null
}
],
"attachments": [
"string"
]
}
}
POST /v1/einvoices/check
Check an e-invoice
Parse an e-invoice and check the EN 16931 and XRechnung rules; nothing is stored.
Send multipart/form-data with the invoice in the form field file. The response says
whether the invoice is valid (no fatal violation), which profile and syntax it is, the
violations by rule id and the parsed invoice. A file that cannot be read as an e-invoice
or is larger than 20 MB answers 422.
| Required scope | read (admin implies every scope) |
| Idempotency-Key | not used |
| Operation id | check_einvoice_v1_einvoices_check_post |
Request body
multipart/form-data (required): Body_check_einvoice_v1_einvoices_check_post
| Field | Type | Required | Description |
|---|---|---|---|
file |
string | yes | The e-invoice: an XRechnung XML file (UBL or CII) or a ZUGFeRD / Factur-X PDF with the XML embedded. At most 20 MB. |
Example request
curl -X POST "$ERP_URL/v1/einvoices/check" \
-H "Authorization: Bearer $ERP_KEY" \
-F "file=@statement.xml"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | OK | CheckResult |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 409 | The request conflicts with the data: an Idempotency-Key reused with a different request, a closed period, or an integrity rule of the database (conflict, integrity_violation). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"valid": true,
"label": "string",
"profile": "string",
"syntax": "string",
"container": "string",
"attachment": "string",
"violations": [
{
"rule": "string",
"severity": "fatal",
"message": "string",
"location": "string"
}
],
"invoice": {
"syntax": "CII",
"specification_id": "string",
"business_process": "string",
"number": "string",
"issue_date": "2026-09-21",
"type_code": "string",
"currency": "string",
"tax_currency": "string",
"tax_point_date": "2026-09-21",
"tax_point_code": "string",
"due_date": "2026-09-21",
"buyer_reference": "string",
"project_reference": "string",
"contract_reference": "string",
"order_reference": "string",
"sales_order_reference": "string",
"receiving_advice": "string",
"despatch_advice": "string",
"tender_reference": "string",
"invoiced_object": "string",
"accounting_reference": "string",
"payment_terms": "string",
"notes": [
"string"
],
"preceding_invoices": [
{
"number": null,
"issue_date": null
}
],
"seller": {
"name": null,
"trading_name": null,
"identifiers": [
null
],
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"buyer": {
"name": null,
"trading_name": null,
"identifiers": [
null
],
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"payee": {
"name": null,
"trading_name": null,
"identifiers": null,
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"tax_representative": {
"name": null,
"trading_name": null,
"identifiers": null,
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"delivery_date": "2026-09-21",
"period_start": "2026-09-21",
"period_end": "2026-09-21",
"deliver_to": {
"line1": null,
"line2": null,
"line3": null,
"city": null,
"postal_code": null,
"subdivision": null,
"country": null
},
"payment_means": [
{
"code": null,
"text": null,
"account_id": null,
"account_name": null,
"bic": null,
"card_number": null,
"card_holder": null,
"mandate_id": null,
"debited_account": null
}
],
"remittance_information": "string",
"creditor_reference_id": "string",
"allowances_charges": [
{
"charge": null,
"amount": null,
"base_amount": null,
"percent": null,
"vat_category": null,
"vat_rate": null,
"reason": null,
"reason_code": null
}
],
"totals": {
"line_total": null,
"allowance_total": null,
"charge_total": null,
"tax_exclusive": null,
"tax_total": null,
"tax_total_accounting": null,
"tax_inclusive": null,
"prepaid": null,
"rounding": null,
"payable": null,
"third_party_payments": null
},
"vat_breakdown": [
{
"taxable_amount": null,
"tax_amount": null,
"category": null,
"rate": null,
"exemption_reason": null,
"exemption_reason_code": null
}
],
"lines": [
{
"id": null,
"note": null,
"quantity": null,
"unit_code": null,
"net_amount": null,
"order_line_reference": null,
"accounting_reference": null,
"period_start": null,
"period_end": null,
"allowances_charges": null,
"net_price": null,
"price_discount": null,
"gross_price": null,
"base_quantity": null,
"vat_category": null,
"vat_rate": null,
"name": null,
"description": null,
"seller_item_id": null,
"buyer_item_id": null,
"standard_item_id": null,
"classifications": null,
"origin_country": null
}
],
"attachments": [
"string"
]
}
}
GET /v1/invoices/{invoice}/xrechnung
Issue a sales invoice as XRechnung
XRechnung 3.0 (CII) for a posted sales invoice or credit note of a German entity.
The output is checked with the same EN 16931 and XRechnung rules as received
invoices; format=xml refuses (422) an invoice that breaks a fatal rule, for
example a customer without a Leitweg-ID or buyer reference (BR-DE-15) or an entity
without a registered bank account (BR-DE-1). format=json shows the check. 422 also
for a document that is not a sales invoice or credit note or whose entity is not German;
409 when it is not posted, and 409 invoice_content_incomplete when the entity's or the
customer's record lacks content the law requires on an invoice (missing lists each field;
see missing_content on the document).
Archived as issued. The first format=xml stores the file with its SHA-256 and links it
to the document (GET /v1/documents/{id}/files, source archived_output); later requests
return those bytes, as for the PDF (GET /v1/documents/{id}/pdf). The first output needs the
post scope and an active organization (409 not_issued otherwise); a test copy issues
no e-invoice (409, ADR-0039).
| Required scope | read (admin implies every scope) |
| Operation id | xrechnung_v1_invoices__invoice__xrechnung_get |
Parameters
| In | Name | Type | Required | Description |
|---|---|---|---|---|
| path | invoice |
string | yes | Document id (uuid) or number, e.g. INV-2026-000001. |
| query | format |
"json" | "xml" |
xml (default): the XRechnung file as an attachment; json: the check result (valid flag, violations and the invoice model). (default "xml") |
Example request
curl "$ERP_URL/v1/invoices/INV-2026-000001/xrechnung" \
-H "Authorization: Bearer $ERP_KEY"
Responses
| Status | Meaning | Body |
|---|---|---|
| 200 | XRechnung 3.0 CII. | XRechnungOut, application/xml |
| 401 | Missing or invalid API key (unauthorized). |
ErrorEnvelope |
| 403 | The caller lacks the required scope (missing_right, with scope), the key belongs to no person where a person is needed (forbidden), or the approval policy denies the action (policy_denied, with action and rule_id). |
ErrorEnvelope |
| 404 | The resource does not exist, or belongs to another organization (not_found). |
ErrorEnvelope |
| 422 | Validation failed: the error envelope (validation_failed). For a malformed body or parameter its message is in sentences ("Line 2: the quantity must be above zero") and fields lists each error with pydantic's loc, type and msg beside its sentence (message) and its parts, to word it in another language: items (name and number from 1: line 2), field (its name as sent) and the rule it breaks with its limit, count and choices (none for a validator's own sentence); FastAPI's own detail list stays beside the envelope. |
HTTPValidationError |
Example response (shape)
{
"filename": "string",
"valid": true,
"violations": [
{
"rule": "string",
"severity": "fatal",
"message": "string",
"location": "string"
}
],
"invoice": {
"syntax": "CII",
"specification_id": "string",
"business_process": "string",
"number": "string",
"issue_date": "2026-09-21",
"type_code": "string",
"currency": "string",
"tax_currency": "string",
"tax_point_date": "2026-09-21",
"tax_point_code": "string",
"due_date": "2026-09-21",
"buyer_reference": "string",
"project_reference": "string",
"contract_reference": "string",
"order_reference": "string",
"sales_order_reference": "string",
"receiving_advice": "string",
"despatch_advice": "string",
"tender_reference": "string",
"invoiced_object": "string",
"accounting_reference": "string",
"payment_terms": "string",
"notes": [
"string"
],
"preceding_invoices": [
{
"number": null,
"issue_date": null
}
],
"seller": {
"name": null,
"trading_name": null,
"identifiers": [
null
],
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"buyer": {
"name": null,
"trading_name": null,
"identifiers": [
null
],
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"payee": {
"name": null,
"trading_name": null,
"identifiers": null,
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"tax_representative": {
"name": null,
"trading_name": null,
"identifiers": null,
"legal_id": null,
"vat_id": null,
"tax_id": null,
"legal_info": null,
"electronic_address": null,
"address": null,
"contact": null
},
"delivery_date": "2026-09-21",
"period_start": "2026-09-21",
"period_end": "2026-09-21",
"deliver_to": {
"line1": null,
"line2": null,
"line3": null,
"city": null,
"postal_code": null,
"subdivision": null,
"country": null
},
"payment_means": [
{
"code": null,
"text": null,
"account_id": null,
"account_name": null,
"bic": null,
"card_number": null,
"card_holder": null,
"mandate_id": null,
"debited_account": null
}
],
"remittance_information": "string",
"creditor_reference_id": "string",
"allowances_charges": [
{
"charge": null,
"amount": null,
"base_amount": null,
"percent": null,
"vat_category": null,
"vat_rate": null,
"reason": null,
"reason_code": null
}
],
"totals": {
"line_total": null,
"allowance_total": null,
"charge_total": null,
"tax_exclusive": null,
"tax_total": null,
"tax_total_accounting": null,
"tax_inclusive": null,
"prepaid": null,
"rounding": null,
"payable": null,
"third_party_payments": null
},
"vat_breakdown": [
{
"taxable_amount": null,
"tax_amount": null,
"category": null,
"rate": null,
"exemption_reason": null,
"exemption_reason_code": null
}
],
"lines": [
{
"id": null,
"note": null,
"quantity": null,
"unit_code": null,
"net_amount": null,
"order_line_reference": null,
"accounting_reference": null,
"period_start": null,
"period_end": null,
"allowances_charges": null,
"net_price": null,
"price_discount": null,
"gross_price": null,
"base_quantity": null,
"vat_category": null,
"vat_rate": null,
"name": null,
"description": null,
"seller_item_id": null,
"buyer_item_id": null,
"standard_item_id": null,
"classifications": null,
"origin_country": null
}
],
"attachments": [
"string"
]
}
}
Schemas
Body_check_einvoice_v1_einvoices_check_post
| Field | Type | Required | Description |
|---|---|---|---|
file |
string | yes | The e-invoice: an XRechnung XML file (UBL or CII) or a ZUGFeRD / Factur-X PDF with the XML embedded. At most 20 MB. |
Body_import_einvoice_v1_documents_einvoice_post
| Field | Type | Required | Description |
|---|---|---|---|
entity |
string | yes | Code of the entity that receives the bill, e.g. DE01. |
file |
string | yes | The e-invoice: an XRechnung XML file (UBL or CII) or a ZUGFeRD / Factur-X PDF with the XML embedded. At most 20 MB. |
vendor |
string or null | Vendor code, e.g. V-IT; default: the vendor is found by the seller's VAT id, then by IBAN. |
|
create_vendor |
boolean | Create an unknown vendor as a draft vendor from the seller's details (true, default); false answers status needs_review instead. (default true) |
|
submit |
boolean | true: also submit the bill through the approval policy; false (default): leave it a draft. (default false) |
XRechnungOut
| Field | Type | Required | Description |
|---|---|---|---|
filename |
string | yes | Name of the XRechnung file, e.g. xrechnung-INV-2026-000001.xml. |
valid |
boolean | yes | true when no fatal rule is broken. |
violations |
array of Violation |
yes | The rules the invoice breaks, by rule id. |
invoice |
Invoice |
yes | The invoice in EN 16931 terms as written to the file. |