Skip to main content
New German e-invoicing mandate from 2027: Kontier issues XRechnung and ZUGFeRD natively German e-invoicing 2027: XRechnung native
Developers

The API is the product.

Five steps from an empty organization to the first compliant invoice. One data model for finance, engineering and ops: documented, versioned, replay-safe.

Open the API reference
REST · v1 OpenAPI 3.1 Webhooks 144 events EU hosting · GDPR-native
Quick start

Five steps to the first invoice.

No setup wizard, no console clicking. Everything Kontier can do is an API call. Each step shows its main call, with the follow-up calls as comments underneath.

  1. customer.created

    Create the customer

    customer_type drives the tax treatment. A business customer in another EU country needs an identifier such as its VAT number, and the VIES check starts on its own once the customer exists, if the workspace has it enabled.

    terminal
    curl -X POST https://api.kontier.eu/v1/customers \  -H "Authorization: Bearer sk_test_…" \  -H "Idempotency-Key: 7f3c9a1e-4b2d-4c8e-9f10-2a6b8d3e5c71" \  -d '{"name":"Zehetbauer IT-Services GmbH","email":"billing@example.com",       "customer_type":"BUSINESS",       "billing_address":{"line1":"Hauptstrasse 1","city":"Vienna","postal_code":"1010","country":"AT"},       "identifiers":[{"kind":"AT_UID","value":"ATU12345678"}]}'→ 201 · customer.created
  2. product.created

    Define the product

    The billable unit. pricing_model decides how a tier ladder is read: VOLUME, STAIRCASE or PACKAGE. Price, meter and publish are one call each.

    terminal
    curl -X POST https://api.kontier.eu/v1/products \  -H "Idempotency-Key: 2b81d4f0-6e3a-4f5b-8c2d-9a1e7b4c6d20" \  -d '{"name":"API Platform","pricing_model":"STAIRCASE",       "quantity_source":"METERED","unit_label":"call"}'# then: POST /v1/prices, POST /v1/meters, POST /v1/changes→ 201 · product.created · status: draft
  3. plan.created

    Version the plan

    The plan bundles products with their included quantities. Every publish is a new version, and each subscription line stays pinned to its version until you say otherwise.

    terminal
    curl -X POST https://api.kontier.eu/v1/plans \  -H "Idempotency-Key: 9c02aa17-3d5e-4a7b-b1c4-6e8f0a2d4b93" \  -d '{"name":"Pro","price_cadence_unit":"month"}'# then: POST /v1/plans/{id}/products  {"included_quantity":"10000"}→ 201 · plan.created
  4. subscription.activated

    Start the subscription

    The subscription starts as a draft. Revision 1 states its phases, such as a trial and the paid term, and /activate puts them in force. Every later change is a new revision, never an overwrite.

    terminal
    curl -X POST https://api.kontier.eu/v1/subscriptions \  -H "Idempotency-Key: e51f7b93-8a2c-4d6e-a0b3-5c7d9e1f3a48" \  -d '{"customer_id":"0f8fad5b-d9cb-469f-a165-70867728950e","currency":"EUR"}'# then: PUT …/revisions/draft, POST …/activate→ 201 · status: DRAFT  →  200 · subscription.activated
  5. invoice.drafted

    Send usage, get an invoice

    quantity is a string, so decimals survive the wire. The in-body idempotency_key makes the retry after a timeout safe: the same key counts once.

    terminal Sample data
    curl -X POST https://api.kontier.eu/v1/usage-events \  -H "Idempotency-Key: 4d9e2f61-7b3a-4c58-9e0d-1f6a8b2c7e35" \  -d '{"customer_id":"0f8fad5b-…","product_id":"3f2a8c1e-…",       "subscription_id":"5d0b6a0e-…","metric_key":"api_calls",       "quantity":"18402","idempotency_key":"sub-5d0b-api_calls-2026-11"}'→ 201 · recorded→ period close · invoice.drafted · €33.61 + €6.39 VAT = €40.00
Reliability

What the API guarantees.

Commitments, not a feature list: what every response, every error and every webhook is bound to honor.

Webhooks

Signed, at-least-once, replayable.

HMAC-SHA256 over the timestamp and the raw body, secret prefixed whsec_. Verify X-Webhook-Signature-V1 and reject timestamps outside ±5 minutes, and a captured delivery cannot be replayed at you. Six delivery attempts (now, 1m, 5m, 30m, 2h, 12h), dedup on idempotency_key. No signing secret means no delivery.

X-Webhook-Timestamp: 1796104803X-Webhook-Signature-V1: v1=b131b63fd94f82f6…{ "type": "invoice.finalized", "schema": "v1", "payload_version": 1, "idempotency_key": "0f3c0c47-…", "payload": { "number": "INV-2026-000123", … } }
Errors

RFC 9457 Problem Details.

Every error is machine-readable: type, title, status, detail, code, plus a request_id for support. No guessing, no regex on error strings.

application/problem+json
Idempotency

Required, not optional.

Idempotency-Key is required on every POST. The key is bound to the SHA-256 of the body: the same key with a different body returns 409. 5xx responses are never cached, so a retry really re-executes.

Idempotency-Key: required
Pagination

Cursor, not offset.

Keyset over (created_at, id), cursor as an opaque token. Stable under parallel inserts; has_more is the authoritative signal, not total_count.

?cursor=…&limit=50 · max 200
Money

Fail closed where it counts.

If the idempotency store briefly falters, operations that move or document money (credits, charges, refunds, credit notes) never run without dedup: they answer 503 with Retry-After. A retry beats a double charge.

503 over a double charge
Versioning

The plan version is pinned.

Every subscription line carries its plan version and stays pinned by default. A publish never alters an issued invoice, and a switch is a new revision, never a side effect. publish-impact shows beforehand what a publish would set off.

GET /v1/plans/{id}/publish-impact
OpenAPI

The spec is the contract.

OpenAPI 3.1, generated straight from the code, not maintained on the side. Over 550 paths, over 750 operations and 144 webhook events, each with its own payload schema. Generate your client from it.

OpenAPI 3.1 · generated from code
E-invoicing

The invoice that passes validation.

XRechnung and ZUGFeRD come out of the same invoice you already produce. No second data path, no export to Excel, no library you have to keep aligned with the KoSIT rules yourself.

From call to valid XML

Generate the document: pick a profile, reference the invoice.

POST /v1/e-invoicing/documents{ "invoice_id": "ad796aee-…",  "profile": "XRECHNUNG_3_0_UBL",  "jurisdiction": "DE" }→ 201 · "quarantined": true · 1 finding

Fetch the raw XML: exactly what the recipient receives.

GET /v1/e-invoicing/documents/{id}/raw→ 200 · application/xml · sha256 ae717a6e…

Read the findings: every violated rule with its id and XPath, not "invalid".

GET /v1/e-invoicing/documents/{id}/findings→ [ { "rule_id": "BR-DE-15", "severity": "ERROR", … } ]

What gets validated

Own rule engine

EN 16931, KoSIT BR-DE and PEPPOL BIS run as rules inside the service. No external schematron service that can be down.

The rules KoSIT actually checks

The BR-DE rules are transcribed from the KoSIT schematron, assertion by assertion. BR-DE-15 requires a buyer reference (BT-10) and leaves its value open: a Leitweg-ID and a purchase-order number both pass. A finding checked that way looks like this:

BR-DE-15 · ERROR Quarantined Sample data
/Invoice/BuyerReference

Buyer reference (BT-10) is missing. Add it on the draft with PATCH /v1/invoices/{id} "buyer_reference", then generate again:

0 findings · deliverable

Quarantine, not a silent failure

Findings are stored per document. A document that breaks the rules is quarantined instead of quietly going out to a public authority.

19 profiles in the catalogue

  • XRECHNUNG_3_0_UBL
  • XRECHNUNG_3_0_CII
  • EN16931_UBL_2_1
  • EN16931_CII_D16B
  • PEPPOL_BIS_BILLING_3_UBL
  • ZUGFERD_2_COMFORT
  • FACTURX_EN16931
  • ZUGFERD_2_XRECHNUNG
  • +11

Marked green: XML-only profiles the service produces itself. The eleven hybrid PDF/A-3 profiles (Factur-X, ZUGFeRD) also need a configured Mustang server.

Artifacts are archived with bytes and a hash chain, so the GoBD question "is this still the same invoice" has an answer.

Everything else lives in the reference.

Complete endpoints, schemas, webhook catalogs and examples, readable without signing up, instantly usable with sandbox keys. And anywhere on this site, pressing Shift + I reveals each artifact's API path, including right here.

Book a demo

A technical demo: 15 minutes with an engineer on your pricing model and tax setup.

How we handle your details: privacy policy.

Prefer email? contact@frontieralgorithmics.com

Message Kontier

Write to us right here. We reply by email, usually within one business day.

How we handle your details: privacy policy.

Personal invitation · 30 days

Try Kontier for 30 days, with a personal invite

We set up a trial account for you and send the invite personally. No credit card, the trial ends on its own.

Your invite arrives within 48 hours at the address you enter, sent by a person, not a script.

Separate from the public 14-day trial, which starts with a card on the pricing page.