API-Referenz
Alle Endpunkte der invoiceapi.io-REST-API, erzeugt aus ihrer OpenAPI-3.1-Beschreibung.
- Basis-URL
https://invoiceapi.io/v1- Authentifizierung
Authorization: Bearer sk_test_… oder sk_live_…- OpenAPI
- OpenAPI 3.1 JSON
Schnellstart: Ihre erste Testrechnung
Vom neuen Konto bis zur ersten Testrechnung aus Ihrem eigenen Code. Sie brauchen dafür nur eine E-Mail-Adresse und den HTTP-Client Ihrer Programmiersprache.
Anmelden
Melden Sie sich unter /login mit Ihrer E-Mail-Adresse an. Wir senden Ihnen einen einmaligen Code per E-Mail. Ist die Adresse neu, legt die Anmeldung Ihr Konto an.
Den Einrichtungsassistenten durchlaufen
Der Assistent fragt nacheinander nach Ihrer Organisation, dem Rechnungssteller, Layout und Nutzungsbedingungen und dem Logo. Zum Schluss erstellt er einen Test-API-Schlüssel. Kopieren Sie den Schlüssel sofort: Er wird nur einmal angezeigt.
Die Vorlagen-ID ermitteln
Die ID steht im curl-Befehl am Ende des Assistenten. Sie können sie auch mit dem Test-API-Schlüssel abfragen: GET /v1/templates liefert jede Vorlage mit ihrer id. Nehmen Sie eine Vorlage, die eine profileId hat. Eine Vorlage ohne Profil beantwortet den Aufruf mit 404 „Template has no associated profile“.
Die erste Rechnung erzeugen
Senden Sie den Rechnungsdatensatz an diesen Endpunkt, mit einem eigenen Idempotency-Key für jede Rechnung. 201 heißt: Die Rechnung wurde erzeugt. 200 heißt: Derselbe Schlüssel kam schon einmal, und Sie erhalten die bereits erzeugte Rechnung zurück.
POST /v1/templates/{id}/invoicesDer Datensatz enthält weder Verkäufer noch Bankverbindung: Beides ergänzt das Rechnungsprofil der Vorlage. Was Sie im Datensatz mitsenden, hat Vorrang vor dem Profil.
{ "buyer": { "name": "Kunde AG", "vatId": "DE987654321", "electronicAddress": "rechnung@kunde.example", "address": { "line1": "Kundenweg 1", "city": "München", "postCode": "80331", "countryCode": "DE" } }, "invoice": { "number": "R-2026-1001", "issueDate": "2026-07-01", "dueDate": "2026-07-31", "currency": "EUR", "buyerReference": "KND-2026-77" }, "items": [ { "name": "Beratung", "quantity": "8", "unit": "HUR", "unitPrice": "120.00", "vatRate": "19" } ], "payment": { "reference": "R-2026-1001" } }Laden Sie die Dateien unter outputs[].url bald herunter, denn die Links laufen ab. Neue Links erhalten Sie jederzeit mit GET /v1/invoices und der id der Rechnung.
Derselbe Aufruf in Ihrer Sprache
Ein SDK brauchen Sie nicht. Jedes Beispiel nutzt den HTTP-Client, den die Sprache mitbringt, und liest Schlüssel und Vorlagen-ID aus den Umgebungsvariablen INVOICEAPI_KEY und TEMPLATE_ID. Das Python-Beispiel setzt einen eigenen User-Agent, weil ein Aufruf mit dem Standard-User-Agent von urllib mit 403 abgewiesen wird.
: "${INVOICEAPI_KEY:?Set INVOICEAPI_KEY and TEMPLATE_ID first.}" "${TEMPLATE_ID:?Set INVOICEAPI_KEY and TEMPLATE_ID first.}" && \ curl -X POST "https://invoiceapi.io/v1/templates/$TEMPLATE_ID/invoices" \ -H "Authorization: Bearer $INVOICEAPI_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: $(uuidgen 2>/dev/null || openssl rand -hex 16)" \ --data-binary @- <<'JSON' { "buyer": { "name": "Kunde AG", "vatId": "DE987654321", "electronicAddress": "rechnung@kunde.example", "address": { "line1": "Kundenweg 1", "city": "München", "postCode": "80331", "countryCode": "DE" } }, "invoice": { "number": "R-2026-1001", "issueDate": "2026-07-01", "dueDate": "2026-07-31", "currency": "EUR", "buyerReference": "KND-2026-77" }, "items": [ { "name": "Beratung", "quantity": "8", "unit": "HUR", "unitPrice": "120.00", "vatRate": "19" } ], "payment": { "reference": "R-2026-1001" } } JSONAusgabeformate
Ohne Angabe erzeugt die API eine ZUGFeRD-PDF. Mit ?output= wählen Sie selbst; der Parameter lässt sich wiederholen, etwa ?output=zugferd_pdf&output=xrechnung_xml.
zugferd_pdf- Die Voreinstellung: PDF/A-3 mit eingebettetem XML, geprüft mit dem KoSIT-Validator und veraPDF.
xrechnung_xml- Das XML für öffentliche Auftraggeber, geprüft mit dem KoSIT-Validator. Es braucht BT-10 (invoice.buyerReference), BT-34 und BT-49 (die elektronischen Adressen von Verkäufer und Käufer). BT-10 und BT-49 stehen im Datensatz oben, BT-34 kommt aus dem Rechnungsprofil der Vorlage.
pdf- Die einfache PDF, ohne Prüfung.
Mögliche Antworten auf den ersten Aufruf
Fehler kommen als application/problem+json mit dem englischen Titel der API.
- 401
Invalid or missing API key - Der Schlüssel fehlt, ist unbekannt oder wurde widerrufen.
- 404
Template not found - Die Vorlagen-ID ist falsch oder gehört nicht zu Ihrer Organisation.
- 404
Template has no associated profile - Die Vorlage hat kein Rechnungsprofil. Nehmen Sie eine Vorlage mit profileId.
- 400
Invalid invoice payload - Der Datensatz passt nicht zum Schema. errors nennt jeden fehlerhaften Pfad mit seiner Meldung.
- 400
Payload is not XRechnung-ready - Sie haben xrechnung_xml angefordert, aber im Datensatz fehlt BT-10, BT-34 oder BT-49.
- 422
Invoice failed compliance validation - Die Rechnung hat die Prüfung nicht bestanden. errors nennt jede verletzte Regel mit ihrer ID, etwa BR-DE-15.
Endpunkte
/templates/{id}/invoicesGenerate an invoice from a template
Generates a ZUGFeRD PDF/A-3, an XRechnung XML and/or a plain PDF from the template and payload (see the `output` parameter for which checks each kind gets). Idempotent per Idempotency-Key: a repeat with the same key and an identical body replays the original invoice with a 200 instead of creating a new one. Supply the optional `deliverEmail` block to also email the finished invoice: delivery is attempted synchronously and its outcome is reported on the 201, but a delivery failure NEVER fails the request — the invoice is archived either way. The seller and the bank details (`iban`, `bic`, `accountName`) come from the template's invoice profile for every field the request leaves out; a field the request sends wins.
Parameter
| Feld | Ort | Erforderlich | Beschreibung |
|---|---|---|---|
| id | path | Erforderlich | Resource id. |
| output | query | — | Repeatable. Which artifact kind(s) to produce. Defaults to zugferd_pdf when omitted. `zugferd_pdf`: a PDF/A-3 with the ZUGFeRD XML embedded; KoSIT checks the XML and veraPDF checks the PDF/A-3U. `xrechnung_xml`: the XRechnung XML, checked by KoSIT only; it needs BT-10 (`invoice.buyerReference`), BT-34 (`seller.electronicAddress`, usually from the template's profile) and BT-49 (`buyer.electronicAddress`), or the request gets a 400 "Payload is not XRechnung-ready". `pdf`: the rendered PDF only, with no embedded XML and no KoSIT or veraPDF check (the renderer's plain PDF, NOT validated), so an invoice that requests only `pdf` has an empty `validation.summary`. |
| Idempotency-Key | header | — | Client-supplied key. A repeat with the same key and body returns the original invoice (200); the same key with a different body returns 409. |
Anfrage
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
| seller | object | — | Optional. Each field you leave out is taken from the template's invoice profile, where the profile has it; a field you send wins. |
| seller.name | string | — | Seller name (BT-27) |
| seller.tradingName | string | — | Seller trading name (BT-28) |
| seller.vatId | string | — | Seller VAT identifier (BT-31) |
| seller.taxNumber | string | — | Seller Steuernummer (BT-32) |
| seller.electronicAddress | string | — | Seller electronic address, scheme EM (BT-34; mandatory for XRechnung) |
| seller.address | object | — | Seller postal address (BG-5) |
| seller.address.line1 | string | — | Street line 1 (BT-35 / BT-50) |
| seller.address.line2 | string | — | Street line 2 (BT-36 / BT-51) |
| seller.address.city | string | — | City (BT-37 / BT-52; BR-DE-3/BR-DE-8) |
| seller.address.postCode | string | — | Post code (BT-38 / BT-53; BR-DE-4/BR-DE-9) |
| seller.address.countryCode | string | — | Country code (BT-40 / BT-55) |
| seller.contact | object | — | Seller contact (BG-6; mandatory per BR-DE-2) |
| seller.contact.name | string | — | Contact point (BT-41; BR-DE-5) |
| seller.contact.phone | string | — | Contact phone (BT-42; BR-DE-6) |
| seller.contact.email | string | — | Contact email (BT-43; BR-DE-7/BR-DE-28) |
| buyer | object | Erforderlich | — |
| buyer.name | string | Erforderlich | Buyer name (BT-44) |
| buyer.vatId | string | — | Buyer VAT identifier (BT-48) |
| buyer.legalRegistrationId | string | — | Buyer legal registration id (BT-47) |
| buyer.electronicAddress | string | — | Buyer electronic address, scheme EM (BT-49; mandatory for XRechnung) |
| buyer.address | object | Erforderlich | Buyer postal address (BG-8) |
| buyer.address.line1 | string | Erforderlich | Street line 1 (BT-35 / BT-50) |
| buyer.address.line2 | string | — | Street line 2 (BT-36 / BT-51) |
| buyer.address.city | string | Erforderlich | City (BT-37 / BT-52; BR-DE-3/BR-DE-8) |
| buyer.address.postCode | string | Erforderlich | Post code (BT-38 / BT-53; BR-DE-4/BR-DE-9) |
| buyer.address.countryCode | string | Erforderlich | Country code (BT-40 / BT-55) |
| invoice | object | Erforderlich | — |
| invoice.number | string | Erforderlich | Invoice number (BT-1) |
| invoice.issueDate | string | Erforderlich | Issue date (BT-2) |
| invoice.dueDate | string | — | Payment due date (BT-9) |
| invoice.currency | "EUR" | Erforderlich | Invoice currency (BT-5); v1 is EUR-only — non-EUR is a documented seam |
| invoice.buyerReference | string | — | Buyer reference (BT-10); Leitweg-ID for B2G; mandatory for XRechnung (BR-DE-15) |
| invoice.paymentTerms | string | — | Payment terms free text (BT-20) |
| invoice.notes | string[] | — | Invoice notes (BT-22) |
| items | object[] | Erforderlich | — |
| items[].name | string | Erforderlich | Item name (BT-153) |
| items[].description | string | — | Item description (BT-154) |
| items[].quantity | string | number | Erforderlich | Invoiced quantity (BT-129); negative lines are permitted |
| items[].unit | "H87" | "C62" | "HUR" | "DAY" | "KGM" | "MTR" | "MTK" | "MTQ" | "LTR" | "MON" | "KMT" | "XPP" | Erforderlich | Unit of measure, UN/ECE Rec 20/21 (BT-130), e.g. H87=piece, HUR=hour |
| items[].unitPrice | string | number | Erforderlich | Item net price (BT-146); must not be negative (BR-27) |
| items[].priceBaseQuantity | string | number | — | Price base quantity (BT-149), default 1 |
| items[].vatRate | string | number | — | VAT rate percent (BT-152), e.g. "19", "7", "0" |
| items[].vatCategory | "S" | "Z" | "E" | "AE" | "K" | "G" | — | VAT category (BT-151, UNTDID 5305); default S when vatRate > 0 |
| items[].exemptionReason | string | — | VAT exemption reason text (BT-120); required for category E, e.g. §19 UStG wording |
| items[].allowances | object[] | — | Line allowances (BG-27) |
| items[].allowances[].amount | string | number | — | Allowance amount (BT-136) |
| items[].allowances[].percent | string | number | — | Allowance percentage of the line gross (BT-138) |
| items[].allowances[].reason | string | — | Allowance reason (BT-139) |
| items[].charges | object[] | — | Line charges (BG-28) |
| items[].charges[].amount | string | number | — | Charge amount (BT-141) |
| items[].charges[].percent | string | number | — | Charge percentage of the line gross (BT-143) |
| items[].charges[].reason | string | — | Charge reason (BT-144) |
| allowances | object[] | — | Document level allowances (BG-20) |
| allowances[].amount | string | number | Erforderlich | Document level allowance amount (BT-92) |
| allowances[].vatCategory | "S" | "Z" | "E" | "AE" | "K" | "G" | Erforderlich | VAT category of the allowance (BT-95; required per BR-32) |
| allowances[].vatRate | string | number | — | VAT rate of the allowance (BT-96) |
| allowances[].reason | string | — | Reason (BT-97) |
| allowances[].reasonCode | string | — | Reason code, UNTDID 5189 (BT-98) |
| charges | object[] | — | Document level charges (BG-21) |
| charges[].amount | string | number | Erforderlich | Document level charge amount (BT-99) |
| charges[].vatCategory | "S" | "Z" | "E" | "AE" | "K" | "G" | Erforderlich | VAT category of the charge (BT-102; required per BR-37) |
| charges[].vatRate | string | number | — | VAT rate of the charge (BT-103) |
| charges[].reason | string | — | Reason (BT-104) |
| charges[].reasonCode | string | — | Reason code, UNTDID 7161 (BT-105) |
| payment | object | — | Optional. `iban`, `bic` and `accountName` you leave out are taken from the profile's payment defaults; a field you send wins. |
| payment.meansCode | "30" | "58" | — | Payment means code, UNTDID 4461 (BT-81); v1 supports credit transfer only |
| payment.iban | string | — | Payment account IBAN (BT-84) |
| payment.bic | string | — | BIC (BT-86) |
| payment.accountName | string | — | Payment account name (BT-85) |
| payment.reference | string | — | Remittance information (BT-83) |
| delivery | object | — | — |
| delivery.date | string | — | Actual delivery date (BT-72) |
| delivery.countryCode | string | — | Deliver-to country (BT-80) |
| totals | object | — | Optional client-side totals; generation is rejected if they mismatch the computed totals |
| totals.taxExclusive | string | number | — | Client-asserted invoice total without VAT (BT-109) |
| totals.totalVat | string | number | — | Client-asserted total VAT (BT-110) |
| totals.taxInclusive | string | number | — | Client-asserted invoice total with VAT (BT-112) |
| deliverEmail | DeliverEmail | — | Optional: email the generated invoice to these recipients. Delivery is attempted synchronously and NEVER fails the request — the invoice is archived either way. |
| deliverEmail.to | string[] | Erforderlich | Recipient addresses; lower-cased. IDN domains must be punycoded. |
| deliverEmail.cc | string[] | — | Carbon-copy addresses; lower-cased. IDN domains must be punycoded. |
| deliverEmail.subjectOverride | string | — | Replaces the generated subject line entirely. |
| deliverEmail.message | string | — | Free-text note rendered above the standard body. |
Antwort
- 200
application/jsonIdempotency-Key replay: the invoice already generated for this key and body. A replay NEVER sends email and never reports delivery — the `deliverEmail` field is absent, even if the replayed request carried a `deliverEmail` block. The original request owns the delivery; consult the invoice to see its state.
Feld Typ Erforderlich Beschreibung id string Erforderlich Invoice id. number string Erforderlich Invoice number (BT-1). mode "live" | "test" Erforderlich — status "generated" | "delivered" | "delivery_failed" Erforderlich — templateVersion integer Erforderlich — createdAt string Erforderlich — validation object Erforderlich — validation.summary string Erforderlich — outputs object[] Erforderlich — outputs[].kind "zugferd_pdf" | "xrechnung_xml" | "pdf" Erforderlich — outputs[].sha256 string Erforderlich — outputs[].bytes integer Erforderlich — outputs[].url string Erforderlich Signed GET URL (expires in <= 15 minutes). - 201
application/jsonInvoice generated. `deliverEmail` reports the delivery outcome, or is null.
Feld Typ Erforderlich Beschreibung id string Erforderlich Invoice id. number string Erforderlich Invoice number (BT-1). mode "live" | "test" Erforderlich — status "generated" | "delivered" | "delivery_failed" Erforderlich — templateVersion integer Erforderlich — createdAt string Erforderlich — validation object Erforderlich — validation.summary string Erforderlich — outputs object[] Erforderlich — outputs[].kind "zugferd_pdf" | "xrechnung_xml" | "pdf" Erforderlich — outputs[].sha256 string Erforderlich — outputs[].bytes integer Erforderlich — outputs[].url string Erforderlich Signed GET URL (expires in <= 15 minutes). deliverEmail DeliverEmailResult | null Erforderlich null unless the request carried a `deliverEmail` block. - 400
application/problem+jsonMalformed payload or deliverEmail block (schema validation failed, after the template's profile filled in the seller and bank details); an unknown `output` kind; or "Payload is not XRechnung-ready" when `xrechnung_xml` is requested without BT-10, BT-34 or BT-49.
- 401
application/problem+jsonMissing or invalid API key (Authorization: Bearer <key>).
- 402
application/problem+jsonMonthly quota exceeded (only enforced when billing is enabled).
- 403
application/problem+jsonRecipient not allowed (`https://invoiceapi.io/problems/recipient-not-allowed`): on the Free plan `deliverEmail` may address only members of your organization, in `to` and `cc`; customers from Starter. Checked before generation, so the request uses no document. Only enforced when billing is enabled.
- 404
application/problem+jsonTemplate, template version, or profile not found.
- 409
application/problem+jsonIdempotency-Key reused with a different request body.
- 422
application/problem+jsonCompliance validation failed (KoSIT / veraPDF findings: each `errors[]` entry names its engine in `source`; the example is a veraPDF rejection), or a live invoice carries the sample seller VAT ID or IBAN (type https://invoiceapi.io/problems/sample-seller-data). To fix the latter, remove `seller` and the bank details (`payment.iban`, `bic`, `accountName`) from the request so the template's profile fills them, or send your own values; if the profile itself carries the sample data, fix it under /profiles.
- 429
application/problem+jsonRate limit exceeded; see the Retry-After header.
/invoicesList invoices
Cursor-paginated. Test-mode invoices are excluded unless mode=test.
Parameter
| Feld | Ort | Erforderlich | Beschreibung |
|---|---|---|---|
| profile | query | — | Filter by profile id. |
| from | query | — | Filter by record creation time (createdAt), lower bound, inclusive (any Date.parse-able value). NOT the invoice issue date (BT-2). |
| to | query | — | Filter by record creation time (createdAt), upper bound, inclusive (any Date.parse-able value). NOT the invoice issue date (BT-2). |
| mode | query | — | live (default) or test. |
| cursor | query | — | Opaque pagination cursor from a previous nextCursor. |
| limit | query | — | Page size, clamped to [1, 100] (default 25). |
Antwort
- 200
application/jsonA page of invoices.
Feld Typ Erforderlich Beschreibung data PublicInvoice[] Erforderlich — data[].id string Erforderlich Invoice id. data[].number string Erforderlich Invoice number (BT-1). data[].mode "live" | "test" Erforderlich — data[].status "generated" | "delivered" | "delivery_failed" Erforderlich — data[].templateVersion integer Erforderlich — data[].createdAt string Erforderlich — data[].validation object Erforderlich — data[].validation.summary string Erforderlich — data[].outputs object[] Erforderlich — data[].outputs[].kind "zugferd_pdf" | "xrechnung_xml" | "pdf" Erforderlich — data[].outputs[].sha256 string Erforderlich — data[].outputs[].bytes integer Erforderlich — data[].outputs[].url string Erforderlich Signed GET URL (expires in <= 15 minutes). nextCursor string | null Erforderlich — - 400
application/problem+jsonInvalid profile/cursor/from/to query parameter.
- 401
application/problem+jsonMissing or invalid API key (Authorization: Bearer <key>).
- 429
application/problem+jsonRate limit exceeded; see the Retry-After header.
/invoices/{id}Retrieve an invoice
Returns invoice metadata with freshly signed artifact URLs.
Parameter
| Feld | Ort | Erforderlich | Beschreibung |
|---|---|---|---|
| id | path | Erforderlich | Resource id. |
Antwort
- 200
application/jsonThe invoice.
Feld Typ Erforderlich Beschreibung id string Erforderlich Invoice id. number string Erforderlich Invoice number (BT-1). mode "live" | "test" Erforderlich — status "generated" | "delivered" | "delivery_failed" Erforderlich — templateVersion integer Erforderlich — createdAt string Erforderlich — validation object Erforderlich — validation.summary string Erforderlich — outputs object[] Erforderlich — outputs[].kind "zugferd_pdf" | "xrechnung_xml" | "pdf" Erforderlich — outputs[].sha256 string Erforderlich — outputs[].bytes integer Erforderlich — outputs[].url string Erforderlich Signed GET URL (expires in <= 15 minutes). - 401
application/problem+jsonMissing or invalid API key (Authorization: Bearer <key>).
- 404
application/problem+jsonNo such invoice for this account.
- 429
application/problem+jsonRate limit exceeded; see the Retry-After header.
/templatesList templates
Unpaginated: org template counts are small (plan-limited).
Antwort
- 200
application/jsonThe account templates.
Feld Typ Erforderlich Beschreibung data PublicTemplate[] Erforderlich — data[].id string Erforderlich — data[].name string Erforderlich — data[].layoutId "classic" | "modern" | "compact" | "bold" | "minimal" Erforderlich — data[].version integer Erforderlich — data[].profileId string — Present only for profile-scoped templates. data[].createdAt string Erforderlich — - 401
application/problem+jsonMissing or invalid API key (Authorization: Bearer <key>).
- 429
application/problem+jsonRate limit exceeded; see the Retry-After header.
/templates/{id}Retrieve a template
Parameter
| Feld | Ort | Erforderlich | Beschreibung |
|---|---|---|---|
| id | path | Erforderlich | Resource id. |
Antwort
- 200
application/jsonThe template.
Feld Typ Erforderlich Beschreibung id string Erforderlich — name string Erforderlich — layoutId "classic" | "modern" | "compact" | "bold" | "minimal" Erforderlich — version integer Erforderlich — profileId string — Present only for profile-scoped templates. createdAt string Erforderlich — - 401
application/problem+jsonMissing or invalid API key (Authorization: Bearer <key>).
- 404
application/problem+jsonNo such template for this account.
- 429
application/problem+jsonRate limit exceeded; see the Retry-After header.
/validateValidate an invoice document
Validates an XRechnung/UBL/CII XML or a ZUGFeRD PDF against KoSIT (Schematron) and veraPDF. Quota-exempt. Findings are translated to DE/EN.
Akzeptierte Content-Types
| Feld | Typ | Erforderlich | Beschreibung |
|---|---|---|---|
| file | string | Erforderlich | The XML or PDF document to validate. |
Antwort
- 200
application/jsonThe validation report.
Feld Typ Erforderlich Beschreibung validation object Erforderlich Raw compliance-engine validation result (engine-specific shape). versions object — — findings object[] Erforderlich — findings[].path string Erforderlich — findings[].bt string — — findings[].code string — — findings[].message object Erforderlich — findings[].message.de string Erforderlich — findings[].message.en string Erforderlich — findings[].untranslated boolean — — - 400
application/problem+jsonEmpty body, or the compliance engine could not decode it.
- 401
application/problem+jsonMissing or invalid API key (Authorization: Bearer <key>).
- 429
application/problem+jsonRate limit exceeded; see the Retry-After header.
- 502
application/problem+jsonThe compliance engine is unreachable.
/healthLiveness and dependency reachability
Public. Reports compliance-engine reachability and engine versions.
Antwort
- 200
application/jsonService health.
Feld Typ Erforderlich Beschreibung status "ok" | "degraded" Erforderlich — compliance "ok" | "unreachable" Erforderlich — versions object — —