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
<? 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.
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.
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' ));
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'
);
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
);
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'
);
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.
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
IVA + IRPF Retention
Canary Islands (IGIC)
Equivalence Surcharge
Exempt Line
// 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:
<? 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.