Zum Inhalt springen
Invoapi

Documentation

Introduction

The E-Invoice API turns a plain JSON description of an invoice into a standards-compliant electronic invoice — and back again. One canonical model feeds every supported format, so adding XRechnung CII alongside XRechnung UBL is a parameter change, not a rewrite.

The base URL for this instance is https://api.invoapi.de. Every response carries an X-Request-ID header that also appears in error bodies.

What “valid” means here

Validation executes the official rule sets — the KoSIT Validator with the XRechnung configuration, the CEN EN 16931 Schematron, and the OpenPeppol BIS Billing rules. When no rule set can run, the response says status: "unsupported_validation" with valid: null rather than reporting an unchecked document as valid. Technical conformance is not by itself a statement about tax or legal acceptance.

Quickstart

Send an invoice, get the XML. Replace the placeholder key with one from your dashboard; everything else is the complete request.

cURL
curl -X POST https://api.invoapi.de/api/v1/generate \
  -H "Authorization: Bearer inv_test_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{
  "format": "xrechnung",
  "syntax": "ubl",
  "version": "3.0.2",
  "invoice": {
    "invoice_number": "RE-2026-0001",
    "issue_date": "2026-08-20",
    "due_date": "2026-09-19",
    "currency": "EUR",
    "buyer_reference": "04011000-12345-34",
    "seller": {
      "name": "Muster GmbH",
      "street": "Musterstraße 1",
      "postal_code": "10115",
      "city": "Berlin",
      "country_code": "DE",
      "vat_id": "DE123456789",
      "email": "rechnung@muster.de",
      "phone": "+49 30 1234567"
    },
    "buyer": {
      "name": "Beispiel GmbH",
      "street": "Teststraße 10",
      "postal_code": "20095",
      "city": "Hamburg",
      "country_code": "DE",
      "vat_id": "DE987654321",
      "email": "kreditoren@beispiel.de"
    },
    "items": [
      {
        "name": "Softwareentwicklung",
        "quantity": 10,
        "unit": "HUR",
        "unit_price": 100,
        "vat_rate": 19
      }
    ],
    "payment": {
      "means_code": "58",
      "iban": "DE02120300000000202051",
      "terms": "Zahlbar innerhalb von 30 Tagen ohne Abzug."
    }
  }
}'

The response contains the generated document, the recomputed totals and the full validation report. Try it live in the playground.

Authentication

The invoicing endpoints require an API key. Create one in the dashboard and send it as a bearer token:

Terminal
# Every invoicing endpoint expects your key
curl -X POST https://api.invoapi.de/api/v1/generate \
  -H "Authorization: Bearer inv_test_your_key_here" \
  -H "Content-Type: application/json" \
  -d '{ "format": "xrechnung", "invoice": { … } }'

# Without one you get 401 UNAUTHORIZED
{ "error": { "code": "UNAUTHORIZED", "message": "This endpoint requires an API key. …" } }

X-API-Key is accepted as an alternative for clients that cannot set the Authorization header. A key is shown once when it is created and stored only as a hash — if you lose it, create a new one and revoke the old.

GET /api/v1/health, GET /api/v1/formats and GET /api/v1/formats/{format} stay public: they describe the service rather than doing work for you. Signed-in browser sessions may also use the endpoints, which is how the generator, validator and converter pages work.

Generate invoice

POST /api/v1/generate

Accepts a canonical invoice and returns a document in the requested format. Totals and the VAT breakdown are always recomputed server-side, so the result satisfies BR-CO-10 through BR-CO-17 by construction — omit totals and taxes from your request.

Parameters

FieldTypeDescription
formatstringxrechnung · zugferd · en16931 · ubl · cii · peppol
syntaxstringubl or cii. Defaults to the format's primary syntax.
versionstringStandard version. Defaults to the registry default.
profilestringZUGFeRD conformance level, e.g. en16931.
outputstringxml (default) or pdf for a hybrid PDF/A-3.
validatebooleanRun the real validator on the result. Default true.
invoiceobjectThe canonical invoice. Required.

Validate invoice

POST /api/v1/validate

Accepts multipart/form-data with a file field, a raw application/xml body, or a JSON wrapper with xml, content_base64 or a canonical invoice. Hybrid ZUGFeRD PDFs have their embedded XML extracted automatically.

Terminal
# Upload a file
curl -X POST https://api.invoapi.de/api/v1/validate \
  -F "file=@invoice.xml"

# Or post the XML directly
curl -X POST https://api.invoapi.de/api/v1/validate \
  -H "Content-Type: application/xml" \
  --data-binary @invoice.xml
200 OK
{
  "status": "invalid",
  "valid": false,
  "detected_format": "xrechnung",
  "syntax": "ubl",
  "version": "3.0.2",
  "result": {
    "summary": { "errors": 1, "warnings": 0, "infos": 1 },
    "issues": [
      {
        "severity": "error",
        "rule": "BR-DE-15",
        "path": "/Invoice[1]",
        "message": "Das Element \"Buyer reference\" (BT-10) muss übermittelt werden.",
        "explanation": "XRechnung requires a buyer reference (BT-10). For German public sector buyers this is the Leitweg-ID that routes the invoice to the right agency.",
        "suggestion": "Set `buyer_reference` to the Leitweg-ID your customer gave you.",
        "field": "buyer_reference",
        "business_term": "BT-10",
        "rule_set": "Schematron rules for Invoice - CIUS XRechnung (UBL)"
      }
    ],
    "coverage_note": "Validated against the XRechnung 3.0.2 rules (KoSIT Schematron) and the CEN EN 16931 rules, plus the UBL 2.1 XML Schema. Technical conformance with these rules is not by itself a statement about tax or legal acceptance."
  }
}

When validation cannot run

If the document is unrecognised, or the validation engine is unreachable, you get an explicit non-answer instead of a guess:

200 OK
{
  "status": "unsupported_validation",
  "valid": null,
  "result": {
    "reason": "The document could not be identified as a supported e-invoice format, so no rule set applies to it."
  }
}

Convert invoice

POST /api/v1/convert

Supply exactly one source — invoice, xml or content_base64 — and a target of json, xml, html or pdf. Semantics the target cannot represent come back in warnings.

Terminal
# XRechnung XML -> canonical JSON
curl -X POST https://api.invoapi.de/api/v1/convert \
  -H "Content-Type: application/json" \
  -d '{ "xml": "<Invoice …>", "target": "json" }'

# Canonical JSON -> XRechnung CII
curl -X POST https://api.invoapi.de/api/v1/convert \
  -H "Content-Type: application/json" \
  -d '{ "invoice": { … }, "target": "xml", "format": "xrechnung", "syntax": "cii" }'

Detect format

POST /api/v1/detect

Identifies a document without validating it. Unrecognised documents come back as "format": "unknown" — never a guess.

Terminal
curl -X POST https://api.invoapi.de/api/v1/detect \
  -F "file=@invoice.pdf"
200 OK
{
  "format": "zugferd",
  "syntax": "cii",
  "version": "2.5.2",
  "confidence": 0.95,
  "profile": "en16931",
  "container": "pdf",
  "embedded_filename": "factur-x.xml",
  "evidence": [
    "CustomizationID (BT-24) is 'urn:cen.eu:en16931:2017'",
    "CII XML embedded in a PDF container as 'factur-x.xml' — this is a hybrid ZUGFeRD / Factur-X invoice"
  ]
}

Render invoice

POST /api/v1/render

Returns the document itself with the matching content type — not a JSON envelope — so it can go straight into an iframe or a file.

Terminal
# HTML
curl -X POST https://api.invoapi.de/api/v1/render \
  -H "Content-Type: application/xml" \
  --data-binary @invoice.xml > invoice.html

# PDF
curl -X POST "https://api.invoapi.de/api/v1/render?output=pdf" \
  -H "Content-Type: application/xml" \
  --data-binary @invoice.xml > invoice.pdf

Calculate totals

POST /api/v1/calculate

Runs the VAT engine without producing a document. Useful for showing a running total in your own UI without reimplementing EN 16931 rounding — note that 3 × 19.99 is exactly 59.97 here, not 59.970000000000006.

Terminal
curl -X POST https://api.invoapi.de/api/v1/calculate \
  -H "Content-Type: application/json" \
  -d '{ "invoice": { "invoice_number": "T-1", "issue_date": "2026-08-20",
        "seller": { "name": "A", "country_code": "DE" },
        "buyer":  { "name": "B", "country_code": "DE" },
        "items": [ { "name": "X", "quantity": 3, "unit_price": 19.99, "vat_rate": 7 } ] } }'
200 OK
{
  "totals": {
    "net": "59.97",
    "tax": "4.20",
    "gross": "64.17",
    "payable": "64.17",
    "currency": "EUR"
  },
  "breakdown": [
    { "category": "S", "rate": "7.00", "taxable_amount": "59.97", "tax_amount": "4.20" }
  ],
  "line_amounts": { "1": "59.97" }
}

XRechnung

The German CIUS of EN 16931, mandatory for invoices to German public sector buyers. Its most commonly hit extra rule is BR-DE-15: a buyer reference (BT-10) is required, and for public buyers that is the Leitweg-ID. If you omit buyer_reference, generation falls back to the invoice number to satisfy BR-DE-15 and returns a warning — pass the Leitweg-ID explicitly for public-sector buyers.

Version
3.0.2
Syntax
UBL 2.1 and UN/CEFACT CII D16B
Validation
Official KoSIT Validator 1.6.3 with validator-configuration-xrechnung (XRechnung 3.0.2 Schematron 2.5.0 + CEN EN 16931 1.3.15).

ZUGFeRD / Factur-X

A hybrid invoice: a human readable PDF with the structured XML embedded as factur-x.xml. Profiles EN16931, XRECHNUNG, BASIC and EXTENDED are implemented; MINIMUM and BASIC WL return CAPABILITY_NOT_SUPPORTED rather than a partial document.

Version
2.5.2
Syntax
CII D16B, optionally inside a PDF/A-3 container
Validation
CEN EN 16931 CII Schematron; the XRECHNUNG profile additionally runs the XRechnung rules. FeRD's profile-specific Schematron is not redistributable, so profile-only rules are not checked and PDF/A-3 conformance of the container is not verified.

EN 16931

The European semantic core model that every other format on this list narrows. All BT/BG business terms in the canonical model map to it directly.

Version
2017 / A1
Syntax
UBL 2.1 and CII D16B
Validation
CEN EN 16931 Schematron 1.3.15 plus the matching XML Schema.

UBL 2.1

OASIS Universal Business Language. The generator emits elements in the exact order the XSD sequence requires, which is the most common cause of hand-built UBL failing schema validation.

Version
2.1
Syntax
Invoice and CreditNote
Validation
UBL 2.1 XML Schema plus the CEN EN 16931 Schematron.

UN/CEFACT CII

The syntax underneath ZUGFeRD and the CII flavour of XRechnung. Structured as three trade sections — agreement, delivery and settlement — rather than UBL's flatter layout.

Version
D16B
Syntax
CrossIndustryInvoice
Validation
CII D16B XML Schema plus the CEN EN 16931 CII Schematron.
Source
unece.org

Peppol BIS Billing 3.0

Document creation, parsing, conversion and validation only. No Access Point transmission is implemented — nothing is sent to the Peppol network. Note that Peppol rejects the 'EM' e-mail address scheme, so electronic addresses are mapped to a routable ISO 6523 scheme where one can be derived.

Version
3.0
Syntax
UBL 2.1
Validation
CEN EN 16931 UBL Schematron plus the official PEPPOL-EN16931-UBL rules (peppol-bis-invoice-3 v3.0.20), compiled from source at setup time.

Invoice model

One shape covers every format. Fields carry their EN 16931 business term so the mapping back to the standard is always traceable. camelCase keys are accepted too.

The example below uses the compact shorthand: items (also lines), the line's unit, price and vat, and flat address keys on a party. The canonical names — line_items, unit_code, unit_price, vat_rate and a nested address object — are what the OpenAPI schema lists, and both forms are accepted. Unknown keys are rejected, so a typo fails loudly instead of being ignored.

Canonical invoice
{
  "invoice_number": "RE-2026-0001",     // BT-1  required
  "type": "invoice",                    //       "invoice" | "credit_note"
  "issue_date": "2026-08-20",           // BT-2  required
  "due_date": "2026-09-19",             // BT-9
  "currency": "EUR",                    // BT-5
  "buyer_reference": "04011000-12345",  // BT-10 required by XRechnung
  "purchase_order_reference": "PO-77",  // BT-13

  "seller": {                           // BG-4  required
    "name": "Muster GmbH",              // BT-27
    "street": "Musterstraße 1",         // BT-35
    "postal_code": "10115",             // BT-38
    "city": "Berlin",                   // BT-37
    "country_code": "DE",               // BT-40
    "vat_id": "DE123456789",            // BT-31
    "email": "rechnung@muster.de",      // BT-43
    "phone": "+49 30 1234567"           // BT-42
  },
  "buyer": { /* BG-7, same shape */ },

  "items": [{                           // BG-25 at least one
    "name": "Softwareentwicklung",      // BT-153
    "quantity": 10,                     // BT-129
    "unit": "HUR",                      // BT-130 UN/ECE Rec 20
    "unit_price": 100,                  // BT-146
    "vat_category": "S",                // BT-151 S|Z|E|AE|K|G|O
    "vat_rate": 19,                     // BT-152
    "discount": 0                       // BT-136
  }],

  "allowances": [{ "amount": 50, "reason": "Discount", "vat_rate": 19 }],
  "charges":    [{ "is_charge": true, "amount": 12.5, "reason": "Shipping", "vat_rate": 19 }],

  "payment": {
    "means_code": "58",                 // BT-81 UNTDID 4461
    "iban": "DE02120300000000202051",   // BT-84
    "bic": "BYLADEM1001",               // BT-86
    "terms": "Zahlbar innerhalb von 30 Tagen."  // BT-20
  },

  "notes": [{ "text": "Thank you." }]   // BT-22
}

// Omit "totals" and "taxes" — the VAT engine computes both and its
// values are what end up in the document.

Errors

Every failure uses the same envelope.

422 Unprocessable
{
  "error": {
    "code": "INVALID_INVOICE",
    "message": "The invoice contains validation errors.",
    "details": [
      {
        "field": "buyer_reference",
        "rule": "BR-DE-15",
        "message": "Buyer reference is required."
      }
    ],
    "request_id": "req_2f1c8a94b0d3e5f6a7b8c9d0"
  }
}

Error codes

CodeHTTPMeaning
BAD_REQUEST400The request shape is wrong or a required field is missing.
INVALID_INVOICE422The canonical invoice is structurally or semantically invalid.
INVALID_XML400The document is not well-formed, or contains a DTD / entity declaration.
UNSUPPORTED_FORMAT400The requested format is not one this service implements.
UNSUPPORTED_SYNTAX400The format cannot be expressed in the requested syntax.
UNSUPPORTED_VERSION400The requested standard version is not supported.
CAPABILITY_NOT_SUPPORTED400The operation is genuinely not implemented for this target — it is never faked.
CONVERSION_FAILED422The document could not be mapped onto the canonical model.
DETECTION_FAILED422The container could not be inspected, e.g. a password protected PDF.
RENDERING_FAILED422The invoice could not be rendered as HTML or PDF.
PAYLOAD_TOO_LARGE413The request body exceeds the configured upload limit.
UNSUPPORTED_MEDIA_TYPE415The uploaded file type is not accepted.
VALIDATOR_UNAVAILABLE503The validation engine could not be reached, so no verdict is reported.
VALIDATION_TIMEOUT504Validation exceeded the configured timeout.
GENERATION_NOT_SCHEMA_VALID500A document this service generated failed its own XML Schema. That is our defect, not your data — it is reported instead of being returned as a valid invoice.
INTERNAL_ERROR500An unexpected failure. The request_id identifies it in the service logs.

API reference

The complete machine readable specification is served as OpenAPI 3.1. Import it into your own client, an SDK generator or any API tool.

Service

MethodPathSummary
GET/api/v1/altcha/challengeA proof of work for use without an account
GET/api/v1/healthService health
POST/api/v1/contactSend a contact enquiry

Formats

MethodPathSummary
GET/api/v1/formatsList supported formats
GET/api/v1/formats/{format_id}Describe one format

Invoicing

MethodPathSummary
POST/api/v1/generateGenerate an e-invoice
POST/api/v1/validateValidate an e-invoice
POST/api/v1/detectDetect the format of a document
POST/api/v1/convertConvert between formats
POST/api/v1/renderRender an invoice as a readable document
POST/api/v1/parseParse a document into canonical JSON
POST/api/v1/calculateCalculate totals and VAT

Account

MethodPathSummary
POST/api/v1/auth/signupCreate an account
POST/api/v1/auth/loginSign in
POST/api/v1/auth/logoutSign out
GET/api/v1/account/sessionsWhere you are signed in
DELETE/api/v1/account/sessions/{session_id}End one session
POST/api/v1/account/sessions/revoke-othersSign out everywhere else
POST/api/v1/auth/session/organizationSwitch the active organization
GET/api/v1/auth/sessionCurrent session
POST/api/v1/account/passwordChange your password
POST/api/v1/account/deleteDelete your account and its data
PATCH/api/v1/accountUpdate your account
GET/api/v1/organizations/{organization_id}One organization
PATCH/api/v1/organizations/{organization_id}Rename an organization
GET/api/v1/organizations/{organization_id}/membersOrganization members
GET/api/v1/organizations/{organization_id}/api-keysList API keys
POST/api/v1/organizations/{organization_id}/api-keysCreate an API key
DELETE/api/v1/organizations/{organization_id}/api-keys/{key_id}Revoke an API key
DELETE/api/v1/organizations/{organization_id}/api-keys/{key_id}/recordRemove a revoked API key from the list
GET/api/v1/organizations/{organization_id}/usageUsage for an organization
GET/api/v1/organizations/{organization_id}/usage/eventsRequest history, newest first
GET/api/v1/organizations/{organization_id}/activityAudit events, newest first
GET/api/v1/billingThe current subscription
POST/api/v1/billing/checkoutStart a subscription
POST/api/v1/billing/portalManage the subscription
GET/api/v1/oauth/authorization-requestDescribe a pending authorization
POST/api/v1/oauth/approveApprove a pending authorization
GET/api/v1/organizations/{organization_id}/connectionsPrograms connected through the browser flow
DELETE/api/v1/organizations/{organization_id}/connections/{connection_id}Disconnect a program
POST/api/v1/auth/password-resetRequest a password reset link
POST/api/v1/auth/password-reset/confirmSet a new password with a reset link
POST/api/v1/account/emailRequest an e-mail address change
POST/api/v1/auth/verify-emailConfirm the address an account was opened with
POST/api/v1/auth/verify-email/resendSend the confirmation link again
POST/api/v1/account/email/confirmConfirm a new e-mail address
Documentation · Invoapi