Skip to main content

Quickstart Guide

This guide will walk you through creating a complete, valid FacturaE invoice from scratch.

Prerequisites

Make sure you’ve installed PHP FacturaE via Composer:
composer require php-facturae/php-facturae

Your First Invoice

Let’s create a simple invoice with a seller, buyer, line item, and payment method.

Complete Example

invoice.php
<?php

require_once 'vendor/autoload.php';

use PhpFacturae\Invoice;
use PhpFacturae\Party;

$invoice = Invoice::create('FAC-001')
    ->series('A')
    ->date('2025-03-01')
    ->seller(
        Party::company('B12345678', 'Mi Empresa S.L.')
            ->address('C/ Mayor 10', '28013', 'Madrid', 'Madrid')
            ->email('[email protected]')
    )
    ->buyer(
        Party::person('12345678Z', 'Laura', 'Gómez', 'Ruiz')
            ->address('C/ Sol 3', '28012', 'Madrid', 'Madrid')
            ->email('[email protected]')
    )
    ->line('Diseño de logotipo', price: 450.00, vat: 21)
    ->transferPayment(
        iban: 'ES91 2100 0418 4502 0005 1332',
        dueDate: '2025-03-31'
    )
    ->export('factura.xml');

echo "✓ Invoice generated: factura.xml\n";
Run this script with php invoice.php to generate your first invoice!

Step-by-Step Breakdown

Let’s break down each part of the invoice creation process.
1

Create the invoice

Start by creating an invoice with a unique number:
use PhpFacturae\Invoice;

$invoice = Invoice::create('FAC-001');
The invoice number is required and must be unique. You can add an optional series:
$invoice = Invoice::create('FAC-001')->series('A');
The issue date defaults to the current date/time. Use ->date() to set a specific date.
2

Set invoice date

Specify when the invoice was issued:
$invoice->date('2025-03-01');
You can also pass a DateTimeImmutable object:
$invoice->date(new DateTimeImmutable('2025-03-01'));
3

Define the seller (issuer)

Create the party issuing the invoice. Use Party::company() for legal entities:
use PhpFacturae\Party;

$seller = Party::company('B12345678', 'Mi Empresa S.L.')
    ->address(
        street: 'C/ Mayor 10',
        postalCode: '28013',
        town: 'Madrid',
        province: 'Madrid'
    )
    ->email('[email protected]')
    ->phone('+34 91 123 45 67');

$invoice->seller($seller);
The tax number (B12345678) must be a valid Spanish NIF/CIF or foreign tax ID. The address is required.
For individual persons, use Party::person():
$seller = Party::person(
    taxNumber: '12345678Z',
    name: 'María',
    firstSurname: 'García',
    lastSurname: 'López'
);
4

Define the buyer (recipient)

Similarly, create the party receiving the invoice:
$buyer = Party::person('12345678Z', 'Laura', 'Gómez', 'Ruiz')
    ->address('C/ Sol 3', '28012', 'Madrid', 'Madrid')
    ->email('[email protected]');

$invoice->buyer($buyer);
For foreign buyers, specify the country code:
$buyer = Party::company('FR12345678901', 'Entreprise SAS')
    ->address(
        street: '12 Rue de la Paix',
        postalCode: '75002',
        town: 'Paris',
        province: 'Île-de-France',
        countryCode: 'FRA'  // ISO 3166-1 alpha-3
    );
5

Add line items

Add products or services to the invoice. The ->line() method provides shortcuts for Spanish taxes:
$invoice->line(
    description: 'Diseño de logotipo',
    price: 450.00,      // Unit price (excluding VAT)
    quantity: 1,        // Optional, defaults to 1
    vat: 21             // VAT percentage
);
Add multiple lines:
$invoice
    ->line('Diseño de logotipo', price: 450.00, vat: 21)
    ->line('Hosting anual', price: 120.00, vat: 21)
    ->line('Dominio .es', price: 15.00, vat: 21);
You can specify quantity, discounts, and article codes:
$invoice->line(
    description: 'Lámpara LED',
    price: 20.14,
    quantity: 3,
    vat: 21,
    discount: 10,           // 10% discount
    articleCode: 'LED-001'
);
6

Add payment information

Specify how the invoice should be paid. PHP FacturaE provides shortcuts for common payment methods:Bank transfer:
$invoice->transferPayment(
    iban: 'ES91 2100 0418 4502 0005 1332',
    dueDate: '2025-03-31'
);
Cash payment:
$invoice->cashPayment(dueDate: '2025-03-15');
Card payment:
$invoice->cardPayment(dueDate: '2025-03-01');
Direct debit:
$invoice->directDebitPayment(
    iban: 'ES80 0000 0000 0000 0000 0001',
    dueDate: '2025-03-10'
);
If you don’t specify an amount, it will default to the invoice total. You can split payments manually by calling the method multiple times with different amounts.
7

Export the invoice

Generate and save the XML file:
$invoice->export('factura.xml');
Or get the XML as a string:
$xml = $invoice->toXml();
echo $xml;
The export() and toXml() methods automatically validate the invoice against FacturaE XSD schemas. If validation fails, an InvoiceValidationException is thrown with detailed error messages.

Advanced Tax Scenarios

Spanish Tax Examples

// Professional services with VAT and income tax withholding
$invoice->line(
    description: 'Consultoría informática',
    price: 500.00,
    vat: 21,      // 21% VAT
    irpf: 15      // 15% IRPF withholding
);

Multiple Taxes per Line

For more complex scenarios, use customLine() with TaxBreakdown objects:
use PhpFacturae\Entities\TaxBreakdown;
use PhpFacturae\Enums\Tax;

$invoice->customLine(
    description: 'Producto con múltiples impuestos',
    price: 300.00,
    taxes: [
        new TaxBreakdown(Tax::IGIC, 7),
        new TaxBreakdown(Tax::REIGIC, 0.5),
    ]
);

Split Payments

For invoices paid in installments:
use PhpFacturae\Enums\PaymentMethod;

$invoice->splitPayments(
    method: PaymentMethod::Transfer,
    installments: 3,
    firstDueDate: '2025-04-01',
    intervalDays: 30,
    iban: 'ES91 2100 0418 4502 0005 1332'
);
This creates 3 payments:
  • 2025-04-01: 1/3 of total
  • 2025-05-01: 1/3 of total
  • 2025-05-31: 1/3 of total (with cent adjustment)

Complete Real-World Example

Here’s a more comprehensive invoice with multiple features:
complete-invoice.php
<?php

require_once 'vendor/autoload.php';

use PhpFacturae\Invoice;
use PhpFacturae\Party;
use PhpFacturae\Enums\UnitOfMeasure;

$invoice = Invoice::create('2025-042')
    ->series('A')
    ->date('2025-03-15')
    ->description('Servicios de desarrollo web y hosting')
    
    // Seller (your company)
    ->seller(
        Party::company('B12345678', 'TechDev Solutions S.L.')
            ->tradeName('TechDev')
            ->address('Paseo de la Castellana 123', '28046', 'Madrid', 'Madrid')
            ->email('[email protected]')
            ->phone('+34 91 234 56 78')
            ->website('https://techdev.example.com')
    )
    
    // Buyer
    ->buyer(
        Party::company('B87654321', 'Retail España S.A.')
            ->address('Gran Vía 45', '28013', 'Madrid', 'Madrid')
            ->email('[email protected]')
    )
    
    // Line items
    ->line(
        description: 'Desarrollo web personalizado',
        price: 2500.00,
        quantity: 1,
        vat: 21,
        irpf: 15,
        articleCode: 'DEV-WEB-001'
    )
    ->line(
        description: 'Hosting Premium (12 meses)',
        price: 25.00,
        quantity: 12,
        vat: 21,
        unit: UnitOfMeasure::Month,
        articleCode: 'HOST-PREM'
    )
    ->line(
        description: 'Certificado SSL',
        price: 80.00,
        vat: 21,
        articleCode: 'SSL-CERT'
    )
    
    // General discount
    ->generalDiscount('Cliente VIP', rate: 5)
    
    // Payment in 2 installments
    ->transferPayment(
        iban: 'ES91 2100 0418 4502 0005 1332',
        dueDate: '2025-04-15',
        amount: 1500.00
    )
    ->transferPayment(
        iban: 'ES91 2100 0418 4502 0005 1332',
        dueDate: '2025-05-15'
        // Remaining amount will be calculated automatically
    )
    
    // Export
    ->export('invoices/2025-042.xml');

echo "✓ Invoice 2025-042 generated successfully!\n";
echo "Total lines: " . count($invoice->getLines()) . "\n";
echo "Payment installments: " . count($invoice->getPayments()) . "\n";

Validation

PHP FacturaE automatically validates your invoice when you call toXml() or export().
If validation fails, you’ll get detailed error messages:
use PhpFacturae\Exceptions\InvoiceValidationException;

try {
    $invoice->export('factura.xml');
} catch (InvoiceValidationException $e) {
    echo "Validation errors:\n";
    foreach ($e->getErrors() as $error) {
        echo "  - $error\n";
    }
}
Common validation errors:
  • Missing required fields (seller, buyer, lines)
  • Invalid tax numbers (NIF/CIF format)
  • Invalid postal codes
  • Empty line descriptions
  • Negative prices or quantities

Next Steps

You’ve created your first invoice! Now explore more advanced features:

Digital Signatures

Sign invoices with XAdES-EPES using PKCS#12 or PEM certificates

Corrective Invoices

Create rectificative invoices to correct previous ones

API Reference

Explore the complete API documentation

Tips and Best Practices

Use constants for common values:
define('MY_COMPANY_TAX_NUMBER', 'B12345678');
define('MY_COMPANY_IBAN', 'ES91 2100 0418 4502 0005 1332');

$invoice->seller(
    Party::company(MY_COMPANY_TAX_NUMBER, 'Mi Empresa S.L.')
        ->address('...', '...', '...', '...')
);
Always validate invoice numbers are unique in your application to avoid duplicate invoices with the same number.
Invoice numbering: Spanish law requires sequential numbering within each series. Make sure your application tracks the last used number per series.

Build docs developers (and LLMs) love