Guides

XML Builder

Build electronic invoices with fluent API

XML Builder

Build FatturaPA electronic invoices with a type-safe fluent API.

Setup

import { FatturaBuilder, FatturaSerializer, FatturaValidator } from '@fatturazione-elettronica-aruba/xml-builder';

Building Invoices

Use the flat-input helpers (cedentePrestatore, cessionario) together with addLinea to skip nested objects and manual VAT math. The builder computes DatiRiepilogo and ImportoTotaleDocumento from the lines, and toResult() returns the object, the XML, the validation result and the SDI filename in one call.

import {
  FatturaBuilder,
  cedentePrestatore,
  cessionario,
} from '@fatturazione-elettronica-aruba/xml-builder';

const { xml, filename, validazione } = FatturaBuilder.create()
  .setTrasmissioneB2B({
    idPaese: 'IT',
    idCodice: '01234567890',
    progressivoInvio: '1',
    codiceDestinatario: 'ABC1234',
  })
  .setCedentePrestatore(cedentePrestatore({
    piva: '01234567890',
    denominazione: 'Azienda SRL',
    regimeFiscale: 'RF01',
    indirizzo: 'Via Roma 1', cap: '00100', comune: 'Roma', provincia: 'RM',
    email: 'info@azienda.it',
  }))
  .setCessionarioCommittente(cessionario({
    piva: '09876543210',
    denominazione: 'Cliente SPA',
    indirizzo: 'Via Milano 10', cap: '20100', comune: 'Milano', provincia: 'MI',
  }))
  .setDatiGenerali({
    datiGeneraliDocumento: { tipoDocumento: 'TD01', divisa: 'EUR', data: '2024-01-15', numero: '1' },
  })
  // numeroLinea, prezzoTotale, datiRiepilogo and importoTotaleDocumento are computed automatically
  .addLinea({ descrizione: 'Consulting service', quantita: 10, unitaMisura: 'hours', prezzoUnitario: 100, aliquotaIVA: 22 })
  .toResult();

// validazione.valid === true
// filename === 'IT01234567890_00001.xml'
The helpers coerce values to strings internally, so fields coming from a database (VAT numbers, ZIP codes, phone numbers parsed as number) no longer crash the serializer — you don't need to convert them manually.

The full fluent API below remains supported for advanced cases (explicit DatiRiepilogo, batch invoices, etc.).

Fluent API

const fattura = FatturaBuilder.create()
  .setTrasmissioneB2B({
    idPaese: 'IT',
    idCodice: '01234567890',
    progressivoInvio: '00001',
    codiceDestinatario: 'ABC1234',
  })
  .setCedentePrestatore({
    datiAnagrafici: {
      idFiscaleIVA: { idPaese: 'IT', idCodice: '01234567890' },
      anagrafica: { denominazione: 'Azienda SRL' },
      regimeFiscale: 'RF01',
    },
    sede: {
      indirizzo: 'Via Roma 1',
      cap: '00100',
      comune: 'Roma',
      provincia: 'RM',
      nazione: 'IT',
    },
  })
  .setCessionarioCommittente({
    datiAnagrafici: {
      idFiscaleIVA: { idPaese: 'IT', idCodice: '09876543210' },
      anagrafica: { denominazione: 'Cliente SPA' },
    },
    sede: {
      indirizzo: 'Via Milano 10',
      cap: '20100',
      comune: 'Milano',
      provincia: 'MI',
      nazione: 'IT',
    },
  })
  .setDatiGenerali({
    datiGeneraliDocumento: {
      tipoDocumento: 'TD01',
      divisa: 'EUR',
      data: '2024-01-15',
      numero: '1',
    },
  })
  .setDatiBeniServizi({
    dettaglioLinee: [
      {
        numeroLinea: 1,
        descrizione: 'Consulting service',
        quantita: 10,
        unitaMisura: 'hours',
        prezzoUnitario: 100.0,
        prezzoTotale: 1000.0,
        aliquotaIVA: 22.0,
      },
    ],
    datiRiepilogo: [
      {
        aliquotaIVA: 22.0,
        imponibileImporto: 1000.0,
        imposta: 220.0,
        esigibilitaIVA: 'I',
      },
    ],
  })
  .build();

Public Administration Invoice

For invoices to Public Administration:

const fattura = FatturaBuilder.create()
  .setTrasmissionePA({
    idPaese: 'IT',
    idCodice: '01234567890',
    progressivoInvio: '00001',
    codiceDestinatario: 'ABCDEF', // 6-char IPA code
  })
  // ... rest of the invoice
  .build();

Payment Data

const fattura = FatturaBuilder.create()
  // ... invoice data
  .addDatiPagamento({
    condizioniPagamento: 'TP02', // Full payment
    dettaglioPagamento: [
      {
        modalitaPagamento: 'MP05', // Bank transfer
        importoPagamento: 1220.0,
        iban: 'IT60X0542811101000000123456',
        dataScadenzaPagamento: '2024-02-15',
      },
    ],
  })
  .build();

Batch Invoices (Multiple Bodies)

const fattura = FatturaBuilder.create()
  .setTrasmissioneB2B({ /* ... */ })
  .setCedentePrestatore({ /* ... */ })
  .setCessionarioCommittente({ /* ... */ })
  // First invoice
  .setDatiGenerali({ datiGeneraliDocumento: { numero: '1', /* ... */ } })
  .setDatiBeniServizi({ /* ... */ })
  .newBody() // Start new invoice in batch
  // Second invoice
  .setDatiGenerali({ datiGeneraliDocumento: { numero: '2', /* ... */ } })
  .setDatiBeniServizi({ /* ... */ })
  .build();

// fattura.fatturaElettronicaBody.length === 2

Validation

import { FatturaValidator, validateFattura } from '@fatturazione-elettronica-aruba/xml-builder';

// Method 1: Instance
const validator = new FatturaValidator({ strict: true });
const result = validator.validate(fattura);

// Method 2: Helper
const result = validateFattura(fattura, { validateTotals: true });

// Method 3: Directly from the builder (no need to call build() first)
const result = FatturaBuilder.create()/* ... */.validate({ strict: true });

if (!result.valid) {
  console.log('Errors:', result.errors);
  console.log('Warnings:', result.warnings);
}

Validation Options

const result = validateFattura(fattura, {
  validateTotals: true,       // Verify totals
  validateCodiceFiscale: true, // Verify fiscal code
  validatePartitaIVA: true,   // Verify VAT number
  validateDates: true,        // Verify dates
  strict: false,              // Treat warnings as errors
});

XML Serialization

import { FatturaSerializer } from '@fatturazione-elettronica-aruba/xml-builder';

const serializer = new FatturaSerializer({
  includeSchemaLocation: true,
});

const xml = serializer.serialize(fattura);

console.log(xml);
// <?xml version="1.0" encoding="UTF-8"?>
// <p:FatturaElettronica xmlns:p="..." versione="FPR12">
//   ...
// </p:FatturaElettronica>

Sending Invoice

To send the invoice, use the invoices module:

import { ArubaClient } from '@fatturazione-elettronica-aruba/core';
import { InvoicesClient } from '@fatturazione-elettronica-aruba/invoices';
import { FatturaBuilder, FatturaSerializer, validateFattura } from '@fatturazione-elettronica-aruba/xml-builder';

// 1. Setup client
const client = new ArubaClient({ environment: 'demo' });
await client.auth.signin('username', 'password');
const invoices = new InvoicesClient(client.http);

// 2. Build invoice
const fattura = FatturaBuilder.create()
  .setTrasmissioneB2B({ /* ... */ })
  .setCedentePrestatore({ /* ... */ })
  .setCessionarioCommittente({ /* ... */ })
  .setDatiGenerali({ /* ... */ })
  .setDatiBeniServizi({ /* ... */ })
  .build();

// 3. Validate (optional)
const validation = validateFattura(fattura);
if (!validation.valid) {
  throw new Error(`Invalid invoice: ${JSON.stringify(validation.errors)}`);
}

// 4. Serialize to XML
const serializer = new FatturaSerializer();
const xml = serializer.serialize(fattura);

// 5. Encode to Base64
const base64 = Buffer.from(xml, 'utf-8').toString('base64');

// 6. Send
const result = await invoices.upload({
  dataFile: base64,
  dryRun: false, // true for validation only
});

console.log('Invoice sent:', result.uploadFileName);

Document Types

CodeDescription
TD01Invoice
TD02Advance/Down payment on invoice
TD03Advance/Down payment on fee note
TD04Credit note
TD05Debit note
TD06Fee note
TD16Reverse charge integration (internal)
TD17Integration/self-invoice for foreign services
TD24Deferred invoice
TD25Deferred invoice (triangulation)
TD26Transfer of depreciable assets

Tax Regimes

CodeDescription
RF01Ordinary
RF02Minimum taxpayers
RF04Agriculture
RF19Flat-rate