Skip to main content
This example demonstrates how to create an invoice with proper tax calculations, including tax subtotals, tax categories, and tax schemes.

Complete Example with Tax

import {
  Invoice,
  InvoiceLine,
  Item,
  Price,
  TaxTotal,
  TaxSubtotal,
  TaxCategory,
  TaxScheme,
  ClassifiedTaxCategory,
  LegalMonetaryTotal,
  SellersItemIdentification,
} from 'ubl-builder';

const invoiceOptions = {
  enviroment: '2',
  issuer: {
    prefix: 'INV',
    resolutionNumber: '321654987',
    startDate: '2024-01-01',
    endDate: '2025-12-31',
    startRange: '1000',
    endRange: '5000',
    technicalKey: 'tech-key-123',
  },
  software: {
    id: 'soft-123',
    pin: '123456789',
    providerNit: '900123456-1',
  },
};

const invoice = new Invoice('INV-002', invoiceOptions);

// Set basic fields
invoice.setDefaultProperties();
invoice.setID('INV-002');
invoice.setUBLVersionID('UBL 2.1');
invoice.setIssueDate('2026-03-06');
invoice.setIssueTime('10:30:00-05:00');
invoice.setInvoiceTypeCode('01');
invoice.setDocumentCurrencyCode('USD');

// Create tax category and scheme for line items
const taxScheme = new TaxScheme({
  id: '01',
  name: 'VAT',
});

const classifiedTaxCategory = new ClassifiedTaxCategory({
  id: 'S',
  percent: '19.00',
  taxScheme: taxScheme,
});

// Create invoice line 1 - Product with tax
const item1 = new Item({
  name: 'Laptop Computer',
  sellersItemIdentification: new SellersItemIdentification({
    id: 'PROD-001',
  }),
  classifiedTaxCategory: classifiedTaxCategory,
});

const price1 = new Price({
  priceAmount: '1000.00',
});

const invoiceLine1 = new InvoiceLine({
  id: '1',
  invoicedQuantity: '2',
  lineExtensionAmount: '2000.00',
  item: item1,
  price: price1,
});

invoice.addInvoiceLine(invoiceLine1);

// Create invoice line 2 - Service with tax
const item2 = new Item({
  name: 'Technical Support',
  sellersItemIdentification: new SellersItemIdentification({
    id: 'SERV-001',
  }),
  classifiedTaxCategory: classifiedTaxCategory,
});

const price2 = new Price({
  priceAmount: '500.00',
});

const invoiceLine2 = new InvoiceLine({
  id: '2',
  invoicedQuantity: '1',
  lineExtensionAmount: '500.00',
  item: item2,
  price: price2,
});

invoice.addInvoiceLine(invoiceLine2);

// Calculate tax amounts
const subtotalAmount = 2500.00; // 2000 + 500
const taxRate = 0.19; // 19%
const taxAmount = (subtotalAmount * taxRate).toFixed(2); // 475.00
const totalAmount = (subtotalAmount + parseFloat(taxAmount)).toFixed(2); // 2975.00

// Create tax category for tax total
const taxCategory = new TaxCategory({
  id: 'S',
  percent: '19.00',
  taxScheme: taxScheme,
});

// Create tax subtotal
const taxSubtotal = new TaxSubtotal({
  taxableAmount: subtotalAmount.toFixed(2),
  taxAmount: taxAmount,
  taxCategory: taxCategory,
});

// Create tax total
const taxTotal = new TaxTotal({
  taxAmount: taxAmount,
  taxSubtotals: [taxSubtotal],
});

invoice.addTaxTotal(taxTotal);

// Set monetary totals
const legalMonetaryTotal = new LegalMonetaryTotal({
  lineExtensionAmount: subtotalAmount.toFixed(2),
  taxExclusiveAmount: subtotalAmount.toFixed(2),
  taxInclusiveAmount: totalAmount,
  payableAmount: totalAmount,
});

invoice.setLegalMonetaryTotal(legalMonetaryTotal);

// Set line count
invoice.setLineCountNumeric('2');

// Generate XML
const xml = invoice.getXml(true);
console.log(xml);

Generated XML Output (Excerpt)

The code generates a complete UBL 2.1 invoice with tax calculations:
<?xml version="1.0" encoding="UTF-8"?>
<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:ID>INV-002</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:LineCountNumeric>2</cbc:LineCountNumeric>
  
  <!-- Tax Total -->
  <cac:TaxTotal>
    <cbc:TaxAmount currencyID="USD">475.00</cbc:TaxAmount>
    <cac:TaxSubtotal>
      <cbc:TaxableAmount currencyID="USD">2500.00</cbc:TaxableAmount>
      <cbc:TaxAmount currencyID="USD">475.00</cbc:TaxAmount>
      <cac:TaxCategory>
        <cbc:ID>S</cbc:ID>
        <cbc:Percent>19.00</cbc:Percent>
        <cac:TaxScheme>
          <cbc:ID>01</cbc:ID>
          <cbc:Name>VAT</cbc:Name>
        </cac:TaxScheme>
      </cac:TaxCategory>
    </cac:TaxSubtotal>
  </cac:TaxTotal>
  
  <!-- Legal Monetary Total -->
  <cac:LegalMonetaryTotal>
    <cbc:LineExtensionAmount currencyID="USD">2500.00</cbc:LineExtensionAmount>
    <cbc:TaxExclusiveAmount currencyID="USD">2500.00</cbc:TaxExclusiveAmount>
    <cbc:TaxInclusiveAmount currencyID="USD">2975.00</cbc:TaxInclusiveAmount>
    <cbc:PayableAmount currencyID="USD">2975.00</cbc:PayableAmount>
  </cac:LegalMonetaryTotal>
  
  <!-- Invoice Lines -->
  <cac:InvoiceLine>
    <cbc:ID>1</cbc:ID>
    <cbc:InvoicedQuantity unitCode="EA">2</cbc:InvoicedQuantity>
    <cbc:LineExtensionAmount currencyID="USD">2000.00</cbc:LineExtensionAmount>
    <cac:Item>
      <cbc:Name>Laptop Computer</cbc:Name>
      <cac:SellersItemIdentification>
        <cbc:ID>PROD-001</cbc:ID>
      </cac:SellersItemIdentification>
      <cac:ClassifiedTaxCategory>
        <cbc:ID>S</cbc:ID>
        <cbc:Percent>19.00</cbc:Percent>
        <cac:TaxScheme>
          <cbc:ID>01</cbc:ID>
          <cbc:Name>VAT</cbc:Name>
        </cac:TaxScheme>
      </cac:ClassifiedTaxCategory>
    </cac:Item>
    <cac:Price>
      <cbc:PriceAmount currencyID="USD">1000.00</cbc:PriceAmount>
    </cac:Price>
  </cac:InvoiceLine>
</Invoice>

Tax Structure Explained

Tax Scheme

Defines the type of tax being applied:
const taxScheme = new TaxScheme({
  id: '01',        // Tax scheme identifier (e.g., '01' for VAT)
  name: 'VAT',     // Human-readable tax name
});

Tax Category

Specifies the tax rate and category:
const taxCategory = new TaxCategory({
  id: 'S',              // Standard rate
  percent: '19.00',     // Tax percentage
  taxScheme: taxScheme, // Reference to tax scheme
});

Tax Subtotal

Calculates tax for a specific category:
const taxSubtotal = new TaxSubtotal({
  taxableAmount: '2500.00',  // Amount before tax
  taxAmount: '475.00',       // Calculated tax amount
  taxCategory: taxCategory,   // Tax category applied
});

Tax Total

Aggregates all tax subtotals:
const taxTotal = new TaxTotal({
  taxAmount: '475.00',           // Total tax amount
  taxSubtotals: [taxSubtotal],   // Array of tax subtotals
});
Common Tax Scheme IDs:
  • 01 - VAT (Value Added Tax)
  • 02 - GST (Goods and Services Tax)
  • 03 - ICA (Industry and Commerce Tax)
  • 04 - INC (National Consumption Tax)
Always ensure your tax calculations are accurate:
  1. Calculate the subtotal (sum of all line extension amounts)
  2. Apply the tax rate to get the tax amount
  3. Add tax to subtotal to get the total payable amount

Multiple Tax Rates

You can apply different tax rates to different items:
// Standard rate 19%
const standardTaxCategory = new ClassifiedTaxCategory({
  id: 'S',
  percent: '19.00',
  taxScheme: new TaxScheme({ id: '01', name: 'VAT' }),
});

// Reduced rate 5%
const reducedTaxCategory = new ClassifiedTaxCategory({
  id: 'AA',
  percent: '5.00',
  taxScheme: new TaxScheme({ id: '01', name: 'VAT' }),
});

// Zero rate
const zeroRatedTaxCategory = new ClassifiedTaxCategory({
  id: 'Z',
  percent: '0.00',
  taxScheme: new TaxScheme({ id: '01', name: 'VAT' }),
});
When using multiple tax rates, create separate TaxSubtotal objects for each rate and add them all to the TaxTotal.

Next Steps

Build docs developers (and LLMs) love