Overview
This guide walks you through creating a complete UBL 2.1 invoice with parties, line items, taxes, and monetary totals. By the end, you’ll have a working example that generates valid XML output.
This example demonstrates basic invoice creation. For DIAN-specific features (Colombia), see the advanced guides.
Complete Example
Here’s a full working example that creates a basic invoice:
import { Invoice } from 'ubl-builder' ;
// Create a new invoice with required configuration
const invoice = new Invoice ( 'INV-123456789' , {
timestamp: Date . now (),
enviroment: '2' , // '1' = production, '2' = testing
issuer: {
resolutionNumber: '18760000001' ,
technicalKey: 'tech-key-12345' ,
prefix: 'SETP' ,
startRange: '990000000' ,
endRange: '995000000' ,
startDate: '2019-01-19' ,
endDate: '2030-01-19'
},
software: {
id: 'software-id-12345' ,
pin: 'software-pin-12345' ,
providerNit: '900123456'
}
});
// Set default XML namespaces
invoice . setDefaultProperties ();
// Set basic invoice information
invoice
. setUBLVersionID ( 'UBL 2.1' )
. setProfileID ( 'DIAN 2.1' )
. setID ( 'INV-123456789' )
. setIssueDate ( '2026-03-06' )
. setIssueTime ( '10:30:00-05:00' )
. setInvoiceTypeCode ( '01' ) // 01 = Invoice
. setDocumentCurrencyCode ( 'USD' )
. addNote ( 'Thank you for your business' );
console . log ( invoice . getXml ( true ));
Step-by-Step Breakdown
Import the Invoice class
Start by importing the main Invoice class from the library: import { Invoice } from 'ubl-builder' ;
Create an Invoice instance
Initialize a new invoice with the invoice ID and configuration options: const invoice = new Invoice ( 'INV-123456789' , {
timestamp: Date . now (),
enviroment: '2' , // Testing environment
issuer: {
resolutionNumber: '18760000001' ,
technicalKey: 'tech-key-12345' ,
prefix: 'SETP' ,
startRange: '990000000' ,
endRange: '995000000' ,
startDate: '2019-01-19' ,
endDate: '2030-01-19'
},
software: {
id: 'software-id-12345' ,
pin: 'software-pin-12345' ,
providerNit: '900123456'
}
});
The first parameter is the invoice ID. The second parameter contains configuration for DIAN extensions (required for Colombian e-invoicing).
Set XML namespaces
Add standard UBL 2.1 XML namespace declarations: invoice . setDefaultProperties ();
This adds all required xmlns attributes like xmlns:cac, xmlns:cbc, xmlns:ext, etc.
Configure basic fields
Use the fluent API to set invoice properties: invoice
. setUBLVersionID ( 'UBL 2.1' )
. setProfileID ( 'DIAN 2.1' )
. setIssueDate ( '2026-03-06' )
. setIssueTime ( '10:30:00-05:00' )
. setInvoiceTypeCode ( '01' )
. setDocumentCurrencyCode ( 'USD' );
Generate XML output
Call getXml() to generate the final XML document: const xml = invoice . getXml ( true ); // true = pretty print
console . log ( xml );
Expected XML Output
The code above generates XML similar to:
<? xml version = "1.0" encoding = "UTF-8" standalone = "no" ?>
< Invoice
xmlns = "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2"
xmlns:cac = "urn:oasis:names:specification:ubl:schema:xsd:CommonAggregateComponents-2"
xmlns:cbc = "urn:oasis:names:specification:ubl:schema:xsd:CommonBasicComponents-2" >
< cbc:UBLVersionID > UBL 2.1 </ cbc:UBLVersionID >
< cbc:ProfileID > DIAN 2.1 </ cbc:ProfileID >
< cbc:ID > INV-123456789 </ cbc:ID >
< cbc:IssueDate > 2026-03-06 </ cbc:IssueDate >
< cbc:IssueTime > 10:30:00-05:00 </ cbc:IssueTime >
< cbc:InvoiceTypeCode > 01 </ cbc:InvoiceTypeCode >
< cbc:DocumentCurrencyCode > USD </ cbc:DocumentCurrencyCode >
< cbc:Note > Thank you for your business </ cbc:Note >
</ Invoice >
Adding Parties
Invoices require supplier and customer information:
import {
AccountingSupplierParty ,
AccountingCustomerParty ,
Party ,
PartyTaxScheme ,
PartyLegalEntity ,
PostalAddress
} from 'ubl-builder' ;
// Add supplier party
const supplier = new AccountingSupplierParty ({});
const supplierParty = new Party ({});
supplierParty . addPartyTaxScheme ( new PartyTaxScheme ({
companyID: '900123456' ,
taxScheme: {
id: '01' ,
name: 'IVA'
}
}));
supplierParty . addPartyLegalEntity ( new PartyLegalEntity ({
registrationName: 'Acme Corporation'
}));
supplier . setParty ( supplierParty );
invoice . setAccountingSupplierParty ( supplier );
// Add customer party (similar structure)
const customer = new AccountingCustomerParty ({});
// ... configure customer ...
invoice . setAccountingCustomerParty ( customer );
The party structure in UBL is hierarchical: AccountingSupplierParty contains a Party, which contains PartyTaxScheme, PartyLegalEntity, and other components.
Adding Invoice Lines
Add line items to represent products or services:
import { InvoiceLine } from 'ubl-builder' ;
// Add invoice line 1
invoice . addInvoiceLine ({
id: '1' ,
invoicedQuantity: {
content: '10' ,
attributes: { unitCode: 'EA' } // Each
},
lineExtensionAmount: {
content: '1000.00' ,
attributes: { currencyID: 'USD' }
},
item: {
description: [ 'Premium Widget' ],
name: 'Widget Pro'
},
price: {
priceAmount: {
content: '100.00' ,
attributes: { currencyID: 'USD' }
}
}
});
// Add more lines as needed
invoice . addInvoiceLine ({ /* ... */ });
Adding Tax Totals
Specify tax calculations:
import { TaxTotal , TaxSubtotal , TaxCategory , TaxScheme } from 'ubl-builder' ;
const taxTotal = new TaxTotal ({
taxAmount: {
content: '190.00' ,
attributes: { currencyID: 'USD' }
}
});
taxTotal . addTaxSubtotal ( new TaxSubtotal ({
taxableAmount: {
content: '1000.00' ,
attributes: { currencyID: 'USD' }
},
taxAmount: {
content: '190.00' ,
attributes: { currencyID: 'USD' }
},
taxCategory: new TaxCategory ({
percent: '19.00' ,
taxScheme: new TaxScheme ({
id: '01' ,
name: 'IVA'
})
})
}));
invoice . addTaxTotal ( taxTotal );
Setting Monetary Totals
Define the final amounts:
import { LegalMonetaryTotal } from 'ubl-builder' ;
invoice . setLegalMonetaryTotal ({
lineExtensionAmount: {
content: '1000.00' ,
attributes: { currencyID: 'USD' }
},
taxExclusiveAmount: {
content: '1000.00' ,
attributes: { currencyID: 'USD' }
},
taxInclusiveAmount: {
content: '1190.00' ,
attributes: { currencyID: 'USD' }
},
payableAmount: {
content: '1190.00' ,
attributes: { currencyID: 'USD' }
}
});
Finalizing the Invoice
For DIAN-compliant invoices, call finalizeDocument() to:
Calculate CUFE (Unique Invoice Code) using SHA-384
Generate QR code for verification
Set line count
Assign IDs to invoice lines
invoice . finalizeDocument ();
const finalXml = invoice . getXml ( true );
finalizeDocument() requires complete invoice data including parties, lines, taxes, and monetary totals. Call it only after all data is added.
Output Options
The getXml() method accepts two parameters:
invoice . getXml (
pretty , // boolean: true = formatted, false = compact
headless // boolean: true = no XML declaration, false = include <?xml...?>
);
Examples:
// Pretty-printed with XML declaration (default)
const xml1 = invoice . getXml ( true , false );
// Compact without XML declaration
const xml2 = invoice . getXml ( false , true );
// Default (not pretty, with declaration)
const xml3 = invoice . getXml ();
Common Invoice Type Codes
Code Description 01Invoice 02Debit Note 03Contingency Invoice 91Credit Note
Set using:
invoice . setInvoiceTypeCode ( '01' );
Environment Configuration
Value Environment '1'Production '2'Testing/Staging
const invoice = new Invoice ( 'INV-001' , {
enviroment: '2' , // Testing
// ...
});
Always test invoices in environment '2' before switching to production '1'.
Full Working Example
For a complete, runnable example, check out the online demo or view the test files in the repository:
src/__tests__/invoice.test.ts - Basic invoice tests
src/__tests__/udtTypes/ - Data type examples
Validation
The library includes constructor validation:
// Throws error: invoice ID is required
const invalid = new Invoice ( '' , {});
// Throws error: options object is required
const invalid2 = new Invoice ( 'INV-001' , null );
// Throws error: environment value not allowed
const invalid3 = new Invoice ( 'INV-001' , {
enviroment: '3' // Must be '1' or '2'
});
Next Steps
API Reference Explore all Invoice methods and parameters
DIAN Extensions Learn about CUFE generation, QR codes, and extensions
Common Aggregate Components Deep dive into Party, TaxTotal, and other CACs
Examples See more real-world invoice examples