Kurz gesagt
Für E-Rechnungen ohne Laravel installierst du quittio/core und das Länderpaket quittio/country-de. Statt der Facade erzeugst du einmal eine Instanz mit Quittio::create() und baust Rechnungen mit InvoiceBuilder::make(). ZUGFeRD, XRechnung, Peppol, Validierung und das Lesen von Eingangsrechnungen funktionieren genauso wie in Laravel.
Welche Pakete du brauchst
| Paket | Ohne Laravel | Inhalt |
|---|---|---|
quittio/core | nötig | Datenmodell, Berechnung, CII und UBL, ZUGFeRD/Factur-X, Validierung, Lesen |
quittio/country-de | empfohlen | Pflichtangaben nach UStG, Steuersätze, XRechnung-Regeln, DIN 5008 |
quittio/laravel | nicht nötig | Facade, Konfiguration, Blade, Artisan |
quittio/quittio | nicht nötig | Komplettpaket für Laravel-Projekte |
Voraussetzung ist PHP 8.3 oder neuer mit den Erweiterungen ctype, dom, gd, libxml, mbstring, xmlwriter und zlib. Laravel oder ein anderes Framework wird nicht gebraucht.
Installation
Ein Befehl, keine Konfigurationsdatei:
composer require quittio/core quittio/country-deEin vollständiges Skript
Das Skript erzeugt eine ZUGFeRD-Rechnung (PDF/A-3 mit eingebettetem XML), speichert sie und liest sie zur Kontrolle wieder ein. Es läuft so mit php rechnung.php.
<?php
require __DIR__.'/vendor/autoload.php';
use Quittio\Core\Builder\InvoiceBuilder;
use Quittio\Core\Builder\Party;
use Quittio\Core\Enums\PaymentMeansCode;
use Quittio\Core\Enums\UnitCode;
use Quittio\Core\Quittio;
use Quittio\Core\Tax\CountryDefaultVat;
use Quittio\Country\DE\CountryDE;
$quittio = Quittio::create([], [new CountryDE]);
InvoiceBuilder::useDefaultVat(new CountryDefaultVat($quittio->countries())); // Positionen ohne vat(): 19 %
$invoice = InvoiceBuilder::make()
->number('RE-2026-0120')
->issueDate('2026-10-14')
->deliveryDate('2026-10-14')
->seller(Party::make('Muster GmbH')->vatId('DE123456789')->address('Hauptstraße 1', '12345', 'Musterstadt', 'DE'))
->buyer(Party::make('Kunde AG')->vatId('DE987654321')->address('Bahnhofstraße 5', '54321', 'Beispielstadt', 'DE'))
->line('Consulting', netPrice: '120.00', quantity: 4, unit: UnitCode::Hour)
->payment(PaymentMeansCode::SepaCreditTransfer, iban: 'DE02120300000000202051')
->dueInDays(14)
->build();
$result = $quittio->make($invoice)->render(); // ZUGFeRD: PDF/A-3 mit XML
$path = $result->save(__DIR__.'/invoices/'.$result->filename()); // invoices/Rechnung_RE-2026-0120.pdf
// Zur Kontrolle wieder einlesen, so wie der Empfänger es tut
$read = $quittio->readFile($path);
echo $read->data->totals->amountDue; // EUR 571.20- Ohne Laravel gibt es keine Konfigurationsdatei. Verkäufer und Bankverbindung stehen deshalb im Code.
- useDefaultVat() gibt Positionen ohne eigenen Steuersatz den Standardsatz des Länderpakets, in Deutschland 19 %. Ohne diesen Aufruf schlägt build() bei solchen Positionen fehl.
- render() validiert die Rechnung. Ist sie ungültig, wird eine Exception mit allen Befunden geworfen, bevor eine Datei entsteht.
Was anders ist als in Laravel
| Thema | Laravel | Reines PHP |
|---|---|---|
| Einstieg | Facade Quittio::invoice() | Instanz aus Quittio::create(), Rechnung mit InvoiceBuilder::make() |
| Konfiguration | config/quittio.php | Array oder Config-Objekt an Quittio::create() |
| Verkäufer und Bank | aus der Konfiguration | im Code: ->seller(…) und ->payment(…) |
| Standard-Umsatzsteuer | automatisch | einmal InvoiceBuilder::useDefaultVat(…) beim Start |
| Länderpaket | wird automatisch erkannt | new CountryDE an Quittio::create() übergeben |
| Vorlagen | Blade | PHP-Vorlagen; Twig o. Ä. über eine eigene TemplateEngine |
| Speichern | Storage-Disk | $result->save($pfad) oder file_put_contents() |
Einstellungen übergibst du als Array, zum Beispiel für die Prüfstufen:
$quittio = Quittio::create([
'validation' => ['mode' => 'error', 'levels' => ['L1', 'L2', 'L3', 'L4', 'L7']],
'pdf' => ['b2c_embed_xml' => false],
], [new CountryDE]);XRechnung und Prüfen
Der Formatwechsel ist eine Zeile. Mit check() prüfst du eine Rechnung, ohne ein PDF zu erzeugen:
// XRechnung statt ZUGFeRD
$result = $quittio->make($invoice)->format('xrechnung-cii')->render();
// Nur prüfen, ohne PDF; wirft nie, sondern liefert einen Bericht
$report = $quittio->make($invoice)->format('xrechnung-cii')->check();
$report->isValid();
$report->errors();Auch der Storno-Beleg funktioniert ohne Laravel:
$cancellation = $quittio->cancellation($result->data(), 'ST-2026-0001', reason: 'Doppelt berechnet');Eingangsrechnungen lesen
Seit 2025 muss jedes Unternehmen E-Rechnungen empfangen können. Die Instanz liest CII, UBL und ZUGFeRD und prüft sie auf Wunsch mit allen Stufen:
$read = $quittio->read($uploadedContent); // Inhalt einer XML- oder PDF-Datei
$read = $quittio->readFile('/path/to/invoice.pdf');
$read->data->number; // "RE-2026-0101"
$read->data->seller->name; // der Lieferant
$read->profile; // z. B. "en16931" oder "xrechnung"
$report = $quittio->validateFile($uploadedContent); // alle Prüfstufen auf eine EingangsrechnungIn dein Projekt einbinden
Erzeuge die Instanz einmal beim Start und verwende sie überall. In Symfony, Slim oder einem anderen Framework registrierst du sie als Dienst; ohne Framework genügt eine kleine Fabrik:
final class InvoiceFactory
{
private static ?Quittio $quittio = null;
public static function quittio(): Quittio
{
if (self::$quittio === null) {
self::$quittio = Quittio::create([], [new CountryDE]);
InvoiceBuilder::useDefaultVat(new CountryDefaultVat(self::$quittio->countries()));
}
return self::$quittio;
}
}Was nur mit Laravel geht
- Facade, Konfigurationsdatei und Artisan-Befehle
- Blade-Vorlagen, Queue, Events, Mail und Storage-Integration
- Quittio::fake() und die Test-Assertions (Factories und Szenarien gibt es auch ohne Laravel)
- Quittio Managed (quittio/managed) mit Datenbank, Nummernkreisen und Archiv braucht Laravel 13
Alles, was eine gültige E-Rechnung ausmacht, steckt im Core. Die vollständige Referenz für den Einsatz ohne Laravel steht in der Dokumentation.