Advanced Features

December 18, 2025 ยท View on GitHub

This guide covers advanced features of the UBL library including payment configuration, attachments, allowances/charges, and compliance settings.

UBL Version Configuration

use NumNum\UBL\Invoice;

$invoice = (new Invoice())
    ->setUBLVersionId('2.1')
    ->setCustomizationId('urn:cen.eu:en16931:2017')
    ->setProfileId('urn:fdc:peppol.eu:2017:poacc:billing:01:1.0');

Common Profile IDs

ProfileDescription
urn:fdc:peppol.eu:2017:poacc:billing:01:1.0Peppol BIS Billing 3.0
urn:cen.eu:en16931:2017EN16931 European Standard

Payment Means

Bank Transfer (SEPA)

use NumNum\UBL\PaymentMeans;
use NumNum\UBL\FinancialInstitutionBranch;
use NumNum\UBL\PayeeFinancialAccount;

// Bank account
$financialInstitution = (new FinancialInstitutionBranch())
    ->setId('KREDBEBB');  // BIC code

$payeeAccount = (new PayeeFinancialAccount())
    ->setId('BE68539007547034')  // IBAN
    ->setName('Company Account')
    ->setFinancialInstitutionBranch($financialInstitution);

// Payment means
$paymentMeans = (new PaymentMeans())
    ->setPaymentMeansCode(30)  // 30 = Credit transfer
    ->setPaymentId('INV-2024-001')
    ->setPayeeFinancialAccount($payeeAccount);

$invoice->setPaymentMeans($paymentMeans);

Common Payment Means Codes

CodeDescription
10Cash
20Cheque
30Credit transfer
31Debit transfer
42Payment to bank account
48Bank card
49Direct debit
57Standing agreement
58SEPA credit transfer
59SEPA direct debit

Payment Terms

use NumNum\UBL\PaymentTerms;

$paymentTerms = (new PaymentTerms())
    ->setNote('Net 30 days');

$invoice->setPaymentTerms($paymentTerms);

Document References

Order Reference

$invoice->setOrderReference('PO-2024-001');

Billing Reference (for Credit Notes)

use NumNum\UBL\BillingReference;
use NumNum\UBL\InvoiceDocumentReference;

$invoiceRef = (new InvoiceDocumentReference())
    ->setId('INV-2024-001')
    ->setIssueDate(new \DateTime('2024-01-15'));

$billingReference = (new BillingReference())
    ->setInvoiceDocumentReference($invoiceRef);

$creditNote->setBillingReference($billingReference);

Attachments

Embedded Attachment (Base64)

use NumNum\UBL\AdditionalDocumentReference;
use NumNum\UBL\Attachment;

$pdfContent = file_get_contents('timesheet.pdf');

$attachment = (new Attachment())
    ->setBase64Content(base64_encode($pdfContent))
    ->setMimeCode('application/pdf')
    ->setFilename('timesheet.pdf');

$docReference = (new AdditionalDocumentReference())
    ->setId('ATT-001')
    ->setDocumentType('Timesheet')
    ->setAttachment($attachment);

$invoice->addAdditionalDocumentReference($docReference);

External Reference (URL)

use NumNum\UBL\ExternalReference;

$externalRef = (new ExternalReference())
    ->setUri('https://example.com/documents/timesheet.pdf');

$attachment = (new Attachment())
    ->setExternalReference($externalRef);

$docReference = (new AdditionalDocumentReference())
    ->setId('ATT-002')
    ->setDocumentType('Supporting Document')
    ->setAttachment($attachment);

$invoice->addAdditionalDocumentReference($docReference);

Allowances and Charges

Document Level Allowance (Discount)

use NumNum\UBL\AllowanceCharge;

$discount = (new AllowanceCharge())
    ->setChargeIndicator(false)  // false = allowance/discount
    ->setAllowanceChargeReason('Volume discount')
    ->setAmount(50.00)
    ->setTaxCategory($taxCategory);

$invoice->addAllowanceCharge($discount);

Document Level Charge

$handlingFee = (new AllowanceCharge())
    ->setChargeIndicator(true)  // true = charge
    ->setAllowanceChargeReason('Handling fee')
    ->setAmount(10.00)
    ->setTaxCategory($taxCategory);

$invoice->addAllowanceCharge($handlingFee);

Line Level Allowance

$lineDiscount = (new AllowanceCharge())
    ->setChargeIndicator(false)
    ->setAllowanceChargeReason('Special price')
    ->setAmount(5.00);

$invoiceLine->addAllowanceCharge($lineDiscount);
use NumNum\UBL\LegalEntity;

$legalEntity = (new LegalEntity())
    ->setRegistrationName('Company Legal Name BV')
    ->setCompanyId('0123456789');

$party = (new Party())
    ->setName('Company Name')
    ->setPostalAddress($address)
    ->setLegalEntity($legalEntity);

Party Tax Scheme

use NumNum\UBL\PartyTaxScheme;

$partyTaxScheme = (new PartyTaxScheme())
    ->setCompanyId('BE0123456789')
    ->setTaxScheme($taxScheme);

$party = (new Party())
    ->setName('Company Name')
    ->setPostalAddress($address)
    ->setPartyTaxScheme($partyTaxScheme);

Party Identification

use NumNum\UBL\PartyIdentification;

// GLN (Global Location Number)
$gln = (new PartyIdentification())
    ->setId('5412345000013')
    ->setSchemeId('0088');

// KvK number (Dutch)
$kvk = (new PartyIdentification())
    ->setId('12345678')
    ->setSchemeId('0106');

$party = (new Party())
    ->setName('Company Name')
    ->setPostalAddress($address)
    ->setPartyIdentification($gln);

Common Scheme IDs

Scheme IDDescription
0002System Information et Repertoire des Entreprise et des Etablissements (SIRENE)
0007Organisationsnummer (Swedish)
0009SIRET-CODE
0088EAN Location Code (GLN)
0096DANISH CHAMBER OF COMMERCE Scheme
0106Netherlands Chamber of Commerce (KvK)
0184DIGSTORG
0190Dutch Originator's Identification Number (OIN)
9925Belgian enterprise number (KBO/BCE)

Delivery Information

use NumNum\UBL\Delivery;
use NumNum\UBL\DeliveryLocation;

$deliveryLocation = (new DeliveryLocation())
    ->setAddress($deliveryAddress);

$delivery = (new Delivery())
    ->setActualDeliveryDate(new \DateTime('2024-02-01'))
    ->setDeliveryLocation($deliveryLocation);

$invoice->setDelivery($delivery);

Tax Exemption

$taxCategory = (new TaxCategory())
    ->setId('E')  // E = Exempt
    ->setPercent(0)
    ->setTaxExemptionReason('Export outside EU')
    ->setTaxExemptionReasonCode('VATEX-EU-G')
    ->setTaxScheme($taxScheme);

Common Tax Category IDs

IDDescription
SStandard rate
ZZero rated
EExempt
AEReverse charge
KIntra-community supply
GExport outside EU
OOutside scope of VAT
LCanary Islands
MCeuta and Melilla

Note Fields

$invoice = (new Invoice())
    ->setId('INV-2024-001')
    ->setNote('Payment within 30 days. Thank you for your business.');

Currency

$invoice = (new Invoice())
    ->setId('INV-2024-001')
    ->setDocumentCurrencyCode('EUR');

Tax Currency

For invoices with tax in a different currency:

$invoice->setTaxCurrencyCode('USD');

Rounding

$legalMonetaryTotal = (new LegalMonetaryTotal())
    ->setLineExtensionAmount(999.99)
    ->setTaxExclusiveAmount(999.99)
    ->setTaxInclusiveAmount(1209.99)
    ->setPayableRoundingAmount(0.01)  // Round up 1 cent
    ->setPayableAmount(1210.00);

Generating the XML

use NumNum\UBL\Generator;

$generator = new Generator();

// Generate invoice XML
$invoiceXml = $generator->invoice($invoice);

// Generate credit note XML
$creditNoteXml = $generator->creditNote($creditNote);

// Save to file
file_put_contents('invoice.xml', $invoiceXml);

XML Validation

Validate generated XML against UBL schema:

$generator = new Generator();
$xml = $generator->invoice($invoice);

$dom = new \DOMDocument();
$dom->loadXML($xml);

$schemaUrl = 'http://docs.oasis-open.org/ubl/os-UBL-2.1/xsd/maindoc/UBL-Invoice-2.1.xsd';

if ($dom->schemaValidate($schemaUrl)) {
    echo "Valid UBL document\n";
} else {
    echo "Invalid UBL document\n";
}

Unit Codes

Common unit codes from UN/ECE Recommendation 20:

use NumNum\UBL\UnitCode;

UnitCode::UNIT;   // C62 - Unit
UnitCode::PIECE;  // H87 - Piece
UnitCode::HOUR;   // HUR - Hour
UnitCode::DAY;    // DAY - Day
UnitCode::WEEK;   // WEE - Week
UnitCode::MONTH;  // MON - Month
UnitCode::YEAR;   // ANN - Year
UnitCode::KILOGRAM;  // KGM - Kilogram
UnitCode::METER;     // MTR - Meter
UnitCode::LITER;     // LTR - Liter

Next Steps