invoapi / invoapi-php
PHP client for the invoapi.de e-invoicing API: create and validate XRechnung, ZUGFeRD / Factur-X, EN 16931, UBL, CII and Peppol invoices.
Requires
- php: >=8.1
- ext-curl: *
- ext-json: *
Requires (Dev)
- phpunit/phpunit: ^10.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
PHP-Client für die invoapi.de E-Rechnungs-API: XRechnung, ZUGFeRD / Factur-X, EN 16931, UBL, CII und Peppol erzeugen, gegen die offiziellen Regelwerke prüfen, umwandeln und auslesen.
- PHP 8.1 oder neuer, nur
ext-curlundext-json, keine weiteren Abhängigkeiten - Jede erzeugte Rechnung wird mit dem offiziellen KoSIT-Validator geprüft
- Automatische Wiederholung bei Tempolimit (429) und kurzzeitigen Ausfällen (503)
English: PHP client for the invoapi.de e-invoicing API. Create XRechnung, ZUGFeRD / Factur-X, EN 16931, UBL, CII and Peppol invoices, validate them against the official rule sets (KoSIT), convert and parse them. PHP 8.1+, only
ext-curlandext-json. Install withcomposer require invoapi/invoapi-php; the examples below work the same in any language, see the API documentation.
Installation
composer require invoapi/invoapi-php
Den API-Schlüssel finden Sie im Dashboard unter API-Schlüssel.
Schnellstart: XRechnung erzeugen
<?php require 'vendor/autoload.php'; $invoapi = new Invoapi\Client(getenv('INVOAPI_API_KEY')); $rechnung = $invoapi->generate([ 'invoice_number' => 'RE-2026-0001', 'issue_date' => '2026-10-28', 'due_date' => '2026-11-27', 'currency' => 'EUR', 'buyer_reference' => '04011000-12345-34', // Leitweg-ID, Pflicht bei XRechnung an Behörden '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', 'email' => 'kreditoren@beispiel.de', ], 'items' => [ ['name' => 'Beratung', 'quantity' => 8, 'unit' => 'HUR', 'unit_price' => 145, 'vat_rate' => 19], ], 'payment' => ['means_code' => '58', 'iban' => 'DE02120300000000202051'], ], format: 'xrechnung'); if ($rechnung->isValid()) { $rechnung->saveTo($rechnung->filename()); // RE-2026-0001.xml echo $rechnung->totals()['payable']; // "1380.40" }
Alle Felder der Rechnung beschreibt die API-Dokumentation.
ZUGFeRD-PDF
$pdf = $invoapi->generate($daten, format: 'zugferd', output: 'pdf', profile: 'en16931'); $pdf->saveTo('RE-2026-0001.pdf'); // PDF/A-3 mit eingebettetem XML
Eingehende E-Rechnung prüfen
$bericht = $invoapi->validate(file_get_contents('eingang.xml')); // XML oder ZUGFeRD-PDF if (!$bericht->isValid()) { foreach ($bericht->errors() as $fehler) { echo "{$fehler['rule']}: {$fehler['message']}\n"; // z. B. "BR-DE-15: Leitweg-ID fehlt" } }
isValid() ist nur dann true, wenn ein offizielles Regelwerk tatsächlich gelaufen ist.
Auslesen, erkennen, umwandeln, rechnen
$daten = $invoapi->parse($xmlOderPdf); // Rechnung als Array: Verkäufer, Käufer, Positionen, Summen $format = $invoapi->detect($xmlOderPdf); // ['format' => 'xrechnung', 'syntax' => 'ubl', ...] $cii = $invoapi->convert($ublXml, 'xml', format: 'xrechnung', syntax: 'cii'); $pdf = $invoapi->convert($ublXml, 'pdf', format: 'zugferd'); // XRechnung → ZUGFeRD-PDF $html = $invoapi->render($xmlOderPdf, 'html'); // lesbare Ansicht für Menschen $summen = $invoapi->calculate($daten)['totals']; // kostenlos, zählt nicht aufs Kontingent
Fehlerbehandlung
Jede Ablehnung wirft eine Ausnahme mit der verständlichen Meldung der API:
| Ausnahme | Wann | Was tun |
|---|---|---|
Invoapi\Exception\InvalidRequestException |
Rechnung oder Dokument fehlerhaft (400/422) | getDetails() nennt die Felder |
Invoapi\Exception\AuthenticationException |
Schlüssel falsch, E-Mail unbestätigt, Konto gesperrt | Schlüssel im Dashboard prüfen |
Invoapi\Exception\QuotaExhaustedException |
Gratis-Kontingent aufgebraucht (402) | Tarif wählen: invoapi.de/preise |
Invoapi\Exception\RateLimitException |
Zu viele Aufrufe (429), nach den Wiederholungen | getRetryAfter() Sekunden warten |
Invoapi\Exception\ServiceUnavailableException |
Dienst kurz nicht erreichbar (5xx) | später erneut versuchen |
Invoapi\Exception\ConnectionException |
Keine Verbindung (DNS, TLS, Timeout) | Netzwerk prüfen |
Alle erben von Invoapi\Exception\InvoapiException mit getErrorCode() und getRequestId(). Die Request-ID hilft uns bei Support-Anfragen.
try { $rechnung = $invoapi->generate($daten); } catch (Invoapi\Exception\InvalidRequestException $e) { echo $e->getMessage(); } catch (Invoapi\Exception\InvoapiException $e) { error_log("invoapi: {$e->getMessage()} ({$e->getRequestId()})"); }
Optionen
$invoapi = new Invoapi\Client($apiKey, [ 'timeout' => 90, // Sekunden pro Anfrage 'max_retries' => 2, // Wiederholungen bei 429/503, 0 schaltet sie ab ]);
Tests
composer install vendor/bin/phpunit --testsuite unit # ohne Netzwerk INVOAPI_API_KEY=inv_… vendor/bin/phpunit --testsuite integration # gegen die echte API, verbraucht Kontingent
Lizenz
MIT