Skip to main content

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:
invoice-example.ts
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

1

Import the Invoice class

Start by importing the main Invoice class from the library:
import { Invoice } from 'ubl-builder';
2

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).
3

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.
4

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');
5

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:
output.xml
<?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

CodeDescription
01Invoice
02Debit Note
03Contingency Invoice
91Credit Note
Set using:
invoice.setInvoiceTypeCode('01');

Environment Configuration

ValueEnvironment
'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

Build docs developers (and LLMs) love