---
title: "Create e-invoices in Laravel, step by step · Quittio"
description: "From composer require to a valid ZUGFeRD invoice: installation, company data, first invoice, format choice, error messages, tests and cancellation with Quittio."
canonical_url: "https://quittio.dev/en/guides/create-e-invoices-with-laravel"
locale: en
meta:
  "og:description": "From composer require to a valid ZUGFeRD invoice: installation, company data, first invoice, format choice, error messages, tests and cancellation with Quittio."
  "og:image": "https://quittio.dev/og/quittio-en.jpg"
  "og:image:alt": "Quittio: Invoices, settled. E-invoicing for PHP and Laravel, with a validated sample invoice."
  "og:image:height": "630"
  "og:image:type": image/jpeg
  "og:image:width": "1200"
  "og:title": "Create e-invoices in Laravel, step by step · Quittio"
  "twitter:image": "https://quittio.dev/og/quittio-en.jpg"
  "twitter:image:alt": "Quittio: Invoices, settled. E-invoicing for PHP and Laravel, with a validated sample invoice."
---

> Index of every page on this site: [llms.txt](https://quittio.dev/llms.txt)

# Create an e-invoice in Laravel, step by step

From an empty Laravel app to your first valid e-invoice in about 15 minutes, with real code examples from the documentation.

**How-to**15 Oct 2026 · about 12 minutes

**In short**

Install `quittio/quittio`, enter your company once in `config/quittio.php` and build invoices with `Quittio::invoice()`. `render()` calculates totals and VAT itself, validates the invoice, picks the right format (ZUGFeRD for businesses, XRechnung for German authorities) and returns PDF and XML.

## Requirements

- PHP 8.3 or newer with the extensions `ctype`, `dom`, `gd`, `libxml`, `mbstring`, `xmlwriter` and `zlib`; `intl` is recommended.
- Laravel 13. It also works without Laravel, see [Create e-invoices with plain PHP](https://quittio.dev/en/guides/e-invoices-with-php-without-laravel).
- Optional for the official checks: Java for the KoSIT validator and Docker or a local installation for veraPDF. You do not need either to get started.

## Step 1: Install

The `quittio/quittio` package brings everything a Laravel app needs: the core, the Laravel integration and the German country pack with the mandatory fields under German VAT law.

Terminal

```
composer require quittio/quittio          # core, Laravel integration and German country pack
php artisan quittio:install               # publishes config/quittio.php
```

## Step 2: Enter your company

Every invoice names the seller: your company. You enter it once in `config/quittio.php`, ideally through environment variables. `Quittio::invoice()` then adds it to every invoice.

config/quittio.php

```
// config/quittio.php (excerpt)
'seller' => [
    'name' => env('QUITTIO_SELLER_NAME'),               // Muster GmbH
    'vat_id' => env('QUITTIO_SELLER_VAT_ID'),           // DE123456789
    'tax_number' => env('QUITTIO_SELLER_TAX_NUMBER'),   // 12/345/67890
    'address' => ['line1' => 'Hauptstraße 1', 'postcode' => '12345', 'city' => 'Musterstadt', 'country' => 'DE'],
    'contact' => ['name' => 'Max Muster', 'phone' => '+49 123 456789', 'email' => 'rechnung@muster.de'],
    'bank_accounts' => [
        ['iban' => 'DE02120300000000202051', 'bic' => 'BYLADEM1001', 'name' => 'Muster GmbH'],
    ],
],
```

| Key | Needed | Why |
| --- | --- | --- |
| `name`, `address` | always | German invoices name the seller with the full address |
| `vat_id` or `tax_number` | always | One of them must be on the invoice; the VAT ID is preferred |
| `contact`, `bank_accounts` | recommended | Printed on the invoice; mandatory for XRechnung to authorities |
| `small_business` | small businesses only | `true` marks every invoice as a small business invoice without VAT |

**No VAT ID?**

If you only have a tax number, you also need a trade register number (`legal_registration`) or another identifier (`identifiers`). EN 16931 requires this with rule `BR-CO-26`.

To see the invoice with sample data, use the preview:

$`php artisan quittio:preview --scenario=simple`

## Step 3: Build your first invoice

An invoice starts with `Quittio::invoice()`. You add what belongs to this invoice and end the chain with `render()`:

InvoiceController.php

```
use Quittio\Core\Builder\Party;
use Quittio\Core\Enums\UnitCode;
use Quittio\Country\DE\Tax\VatPreset;
use Quittio\Laravel\Facades\Quittio;

$result = Quittio::invoice()                             // your company from config/quittio.php
    ->number('RE-2026-0042')
    ->deliveryDate('2026-09-30')                         // date of supply, mandatory in Germany
    ->buyer(Party::make('Kunde AG')
        ->vatId('DE987654321')
        ->address('Bahnhofstraße 5', '54321', 'Beispielstadt', 'DE'))
    ->line('Web development', netPrice: '95.00', quantity: 24, unit: UnitCode::Hour,
        description: 'Customer portal, sprint 3')
    ->line('Hosting', netPrice: '49.00', unit: UnitCode::Month)
    ->line('Handbook of VAT law', netPrice: '39.00', vat: VatPreset::Reduced7)   // 7 % instead of 19 %
    ->dueInDays(14)->cashDiscount(days: 7, percent: '2.00')
    ->render();

return $result->download();                              // or $result->save('invoices', '2026/')
```

- `number()` is your invoice number. The invoice date is today unless you call `issueDate()`. Gapless numbering is your app’s job, or that of [Quittio Managed](https://quittio.dev/en/managed).
- `deliveryDate()` is the date of supply. German invoices must state it, even when it equals the invoice date.
- `buyer()` is your customer: name, address and, for businesses, the VAT ID.
- `line()` adds a line. `netPrice` is the net price per unit. Without `quantity` the quantity is 1; without `vat` the standard rate of your country applies (19 % in Germany).
- `dueInDays()` sets the payment term, `cashDiscount()` an early payment discount.

**Amounts as strings**

Pass amounts and quantities as strings (`'95.00'`), never as floats. Floating point numbers cannot store every amount exactly; Quittio rejects them. Quittio always calculates totals and VAT itself, using the rounding rules of EN 16931.

## Step 4: Output, save, send

The result of `render()` holds everything that was produced. Download it, save it or attach it straight to a mail:

InvoiceController.php

```
$result->pdf();            // PDF/A-3 with embedded XML
$result->xml();            // XML
$result->filename();       // Rechnung_RE-2026-0042.pdf
$result->validation();     // validation findings, including warnings

$result->save('invoices', '2026/');                    // to a storage disk
return $result->download();                             // ->stream() / return $result
Mail::to($customer)->send(new YourInvoiceMail($result)); // the result is Attachable
```

Render large volumes in the queue: `Quittio::make($invoice)->queue()->save('invoices', '2026/')`.

## Step 5: The right format

Usually you don’t need to do anything: without a format, Quittio chooses per invoice. For a German seller:

| Customer | Format | Why |
| --- | --- | --- |
| Business in Germany | ZUGFeRD (profile EN 16931) | An e-invoice that is also a readable PDF |
| Public authority (Leitweg-ID as buyer reference) | XRechnung (CII) | Required by public buyers |
| Consumer | PDF | No e-invoicing mandate |
| Small invoice up to €250, marked with `->smallAmount()` | PDF | Small invoices are exempt |
| Business in another EU country | ZUGFeRD (EN 16931) | Readable PDF with standard XML |
| Customer outside the EU | PDF | No EU rules |

If a customer requires a specific format, name it. For German authorities you need the Leitweg-ID:

InvoiceController.php

```
$result = Quittio::invoice()
    ->buyer($authority)
    ->buyerReference('04011000-12345-03')       // Leitweg-ID
    ->line('Consulting', netPrice: '120.00')
    ->render('xrechnung-cii');
```

More in the guide [ZUGFeRD, XRechnung or Peppol](https://quittio.dev/en/guides/zugferd-xrechnung-or-peppol).

## Step 6: Connect your own models

Instead of repeating buyer data for every invoice, let your models provide it. There are three contracts: `ProvidesParty` (customer), `ProvidesInvoiceLine` (lines) and `ProvidesInvoiceData` (a whole invoice, e.g. from an order).

app/Models/User.php

```
use Quittio\Core\Builder\PartyBuilder;
use Quittio\Core\Contracts\ProvidesParty;

class User extends Authenticatable implements ProvidesParty
{
    public function fillParty(PartyBuilder $party): void
    {
        $party->name($this->company ?? $this->name)
            ->vatId($this->vat_id)
            ->address($this->street, $this->postcode, $this->city, $this->country)
            ->electronicAddress($this->email, 'EM');
    }
}

$invoice = Quittio::invoice()
    ->buyer($user)                    // ProvidesParty
    ->lines($order->items)            // ProvidesInvoiceLine
    ->build();
```

The invoice keeps a copy of the values. If the model changes later, invoices already built stay unchanged.

## Step 7: Understand error messages

Every invoice is validated before rendering. If it is invalid, `render()` throws a `ValidationException` with rule code, field and a hint, for example for an XRechnung without Leitweg-ID:

ValidationException

```
The invoice is not valid (2 errors):
[QUITTIO-PROFILE-REQUIRED] BT-10: The field buyerReference (BT-10) is mandatory in profile XRechnung 3.0.
    Provide the field or choose a profile that does not require it.
[BR-DE-15] BT-10: The buyer reference (BT-10) must be provided.
    Set the Leitweg-ID with ->buyerReference('04011000-12345-03').
```

The prefix tells you where a rule comes from: `BR-` from EN 16931, `BR-DE-` from XRechnung, `PEPPOL-` from Peppol, `DE-USTG-` from the German VAT Act and `QUITTIO-` from Quittio itself. Use `check()` instead of `render()` to see all findings at once without anything being thrown.

## Step 8: Test

The most common test checks that your code renders an invoice. `Quittio::fake()` replaces rendering with a fast fake that records every call:

tests/Feature/OrderInvoiceTest.php

```
use Quittio\Laravel\Facades\Quittio;
use Quittio\Laravel\Rendering\RenderedInvoice;

it('renders the invoice of an order', function () {
    $fake = Quittio::fake();

    $this->post('/orders/42/invoice')->assertOk();

    Quittio::assertRenderedCount(1);
    Quittio::assertRendered(fn (RenderedInvoice $r) => $r->format() === 'zugferd'
        && $r->data()->totals->amountDue->isEqualTo('1234.56'));
});
```

To check that the invoice is also a valid e-invoice, use `assertValidEInvoice()` with the official validators. How to run that in CI is covered in [Validating e-invoices](https://quittio.dev/en/guides/validating-e-invoices-kosit-verapdf).

## Step 9: Cancel

An issued invoice is never changed or deleted. To reverse it, you issue a cancellation invoice: a new invoice with its own number that refers to the original.

InvoiceController.php

```
$cancellation = $result->cancel('ST-2026-0001', reason: 'Charged twice');
```

Partial cancellations, signs and corrections are covered in [Cancellation, partial cancellation, correction](https://quittio.dev/en/guides/cancellation-partial-cancellation-correction).

## Where to go next

- If your app issues invoices itself, you need gapless numbers, an archive and immutability. [Quittio Managed](https://quittio.dev/en/managed) handles that; background in [Gapless invoice numbers](https://quittio.dev/en/guides/gapless-invoice-numbers-gobd).
- Adjust logo, colours and texts in the configuration; your own templates are possible.
- Read incoming e-invoices with `Quittio::read()`.

## Frequently asked questions

### **How long does the setup take?**

About 15 minutes: install the package, enter your company data, build the first invoice. The official validators for CI are optional on top.

### **Do I have to write XML myself?**

No. You describe the invoice with the builder; Quittio writes CII or UBL, calculates totals and VAT and, for ZUGFeRD, embeds the XML in a PDF/A-3.

### **Where does the invoice number come from?**

You set it with number(). Quittio open source does not assign numbers; gapless numbering is part of Quittio Managed.

### **Can I change the design?**

Yes, on three levels: logo, colours and texts via configuration, override single parts of the template, or use your own template.

### **Does it work with older Laravel versions?**

Quittio supports the current Laravel major version, currently Laravel 13. The core also runs without Laravel.

## Read next

- [**Formats**

  **ZUGFeRD, XRechnung or Peppol: which format do you need?**

  How the formats differ, who needs which and how Quittio chooses automatically.](https://quittio.dev/en/guides/zugferd-xrechnung-or-peppol)
- [**How-to**

  **Validating e-invoices: KoSIT validator and veraPDF in CI**

  The seven validation levels, setting up the official validators and automating them in GitHub Actions.](https://quittio.dev/en/guides/validating-e-invoices-kosit-verapdf)
- [**Management**

  **Cancellation, partial cancellation, correction: changing invoices correctly**

  Which document fits when, type codes 380, 381 and 384, and VAT aligned to the cent on partial cancellations.](https://quittio.dev/en/guides/cancellation-partial-cancellation-correction)

## Ready for your first invoice?

The complete guide with every option is in the documentation.

[**Open the guide**](https://docs.quittio.dev/getting-started) [**See features**](https://quittio.dev/en/features)

```json
{"@context":"https://schema.org","@graph":[{"@id":"https://quittio.dev/en#website","@type":"WebSite","description":"E-invoicing for PHP and Laravel: create, validate, read and archive ZUGFeRD, XRechnung and Peppol invoices.","inLanguage":"en","name":"Quittio","url":"https://quittio.dev/en","publisher":{"@id":"https://quittio.dev/#identity"},"translationOfWork":{"@id":"https://quittio.dev/#website"}},{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#webpage","@type":"WebPage","dateModified":"2026-10-15","datePublished":"2026-10-15","description":"From composer require to a valid ZUGFeRD invoice: installation, company data, first invoice, format choice, error messages, tests and cancellation with Quittio.","name":"Create e-invoices in Laravel, step by step","url":"https://quittio.dev/en/guides/create-e-invoices-with-laravel","breadcrumb":{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#breadcrumb"},"isPartOf":{"@id":"https://quittio.dev/en#website"},"potentialAction":[{"@type":"ReadAction","target":["https://quittio.dev/en/guides/create-e-invoices-with-laravel"]}],"primaryImageOfPage":{"@id":"https://quittio.dev/#logo"}},{"@id":"https://quittio.dev/#identity","@type":"Organization","description":"Open-Source-Bibliothek für E-Rechnungen in PHP und Laravel (ZUGFeRD, XRechnung, Peppol) und Quittio Managed.","email":"kontakt@niklasforst.de","legalName":"Niklas Forst – Softwareentwicklung","name":"Quittio","url":"https://quittio.dev","founder":{"@type":"Person","name":"Niklas Forst","url":"https://quittio.dev/ueber"},"logo":{"@id":"https://quittio.dev/#logo"},"sameAs":["https://github.com/Quittio/quittio","https://packagist.org/packages/quittio/quittio"]},{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#article","dateModified":"2026-10-15","datePublished":"2026-10-15","description":"From composer require to a valid ZUGFeRD invoice: installation, company data, first invoice, format choice, error messages, tests and cancellation with Quittio.","headline":"Create an e-invoice in Laravel, step by step","inLanguage":"en","thumbnailUrl":"https://quittio.dev/og/quittio-en.jpg","@type":["Article","TechArticle"],"author":{"@id":"https://quittio.dev/#/schema/person/1"},"image":{"@id":"https://quittio.dev/#/schema/image/1"},"isPartOf":{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#webpage"},"mainEntityOfPage":{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#webpage"},"publisher":{"@id":"https://quittio.dev/#identity"}},{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#breadcrumb","@type":"BreadcrumbList","itemListElement":[{"@type":"ListItem","name":"Home","item":"https://quittio.dev/en","position":1},{"@type":"ListItem","name":"Guides","item":"https://quittio.dev/en/guides","position":2},{"@type":"ListItem","name":"Laravel step by step","position":3}]},{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#/schema/question/1","@type":"Question","inLanguage":"en","name":"How long does the setup take?","acceptedAnswer":{"@type":"Answer","text":"About 15 minutes: install the package, enter your company data, build the first invoice. The official validators for CI are optional on top."}},{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#/schema/question/2","@type":"Question","inLanguage":"en","name":"Do I have to write XML myself?","acceptedAnswer":{"@type":"Answer","text":"No. You describe the invoice with the builder; Quittio writes CII or UBL, calculates totals and VAT and, for ZUGFeRD, embeds the XML in a PDF/A-3."}},{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#/schema/question/3","@type":"Question","inLanguage":"en","name":"Where does the invoice number come from?","acceptedAnswer":{"@type":"Answer","text":"You set it with number(). Quittio open source does not assign numbers; gapless numbering is part of Quittio Managed."}},{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#/schema/question/4","@type":"Question","inLanguage":"en","name":"Can I change the design?","acceptedAnswer":{"@type":"Answer","text":"Yes, on three levels: logo, colours and texts via configuration, override single parts of the template, or use your own template."}},{"@id":"https://quittio.dev/en/guides/create-e-invoices-with-laravel#/schema/question/5","@type":"Question","inLanguage":"en","name":"Does it work with older Laravel versions?","acceptedAnswer":{"@type":"Answer","text":"Quittio supports the current Laravel major version, currently Laravel 13. The core also runs without Laravel."}},{"@id":"https://quittio.dev/#/schema/person/1","@type":"Person","name":"Niklas Forst","url":"https://quittio.dev/ueber"},{"@id":"https://quittio.dev/#logo","@type":"ImageObject","caption":"Quittio","contentUrl":"https://quittio.dev/logo.png","inLanguage":"en","url":"https://quittio.dev/logo.png"},{"@id":"https://quittio.dev/#/schema/image/1","@type":"ImageObject","contentUrl":"https://quittio.dev/og/quittio-en.jpg","inLanguage":"en","url":"https://quittio.dev/og/quittio-en.jpg"}]}
```