
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@pixeldrive/peppol-toolkit
Advanced tools
A TypeScript toolkit for building and reading peppol UBL documents
A TypeScript toolkit for preparing and reading documents for e-invoicing and PEPPOL integration. This library helps you generate PEPPOL-compliant UBL XML invoices from structured data.
PEPPOL (Pan-European Public Procurement On-Line) is a set of specifications that enables cross-border e-procurement in Europe and beyond. This toolkit simplifies the process of creating compliant electronic invoices.
npm install @pixeldrive/peppol-toolkit
import { PeppolToolkit } from '@pixeldrive/peppol-toolkit';
const toolkit = new PeppolToolkit();
const { PeppolToolkit } = require('@pixeldrive/peppol-toolkit');
const toolkit = new PeppolToolkit();
import { PeppolToolkit, Invoice } from '@pixeldrive/peppol-toolkit';
const toolkit = new PeppolToolkit();
const invoice: Invoice = {
ID: 'INV-2024-001',
issueDate: '2024-01-15',
dueDate: '2024-02-15',
invoiceTypeCode: 380,
documentCurrencyCode: 'EUR',
buyerReference: 'PO-12345',
seller: {
endPoint: { scheme: '9925', id: '0123456789' },
legalEntity: {
registrationName: 'Acme Corp',
companyId: '0123456789',
},
name: 'Acme Corp',
address: {
streetName: '123 Seller Street',
cityName: 'Brussels',
postalZone: '1000',
country: 'BE',
},
taxSchemeCompanyID: 'BE0123456789',
identification: [{ id: 'BE0123456789' }],
},
buyer: {
endPoint: { scheme: '9925', id: '9876543210' },
legalEntity: {
registrationName: 'Buyer Ltd',
companyId: '9876543210',
legalForm: 'SRL',
},
name: 'Buyer Ltd',
address: {
streetName: '456 Buyer Avenue',
cityName: 'Amsterdam',
postalZone: '1011',
country: 'NL',
},
taxSchemeCompanyID: 'NL9876543210',
identification: [{ id: 'NL9876543210' }],
},
paymentMeans: [
{
code: '30',
paymentId: 'INV-2024-001',
name: 'Bank Transfer',
financialAccount: {
id: 'BE71 0961 2345 6769',
name: 'Acme Corp',
financialInstitutionBranch: 'GEBABEBB',
},
},
],
paymentTermsNote: 'Payment due within 30 days.',
taxTotal: [
{
taxAmountCurrency: 'EUR',
taxAmount: 210.0,
subTotals: [
{
taxableAmount: 1000,
taxAmount: 210,
taxCategory: { categoryCode: 'S', percent: 21 },
},
],
},
],
legalMonetaryTotal: {
currency: 'EUR',
lineExtensionAmount: 1000,
taxExclusiveAmount: 1000,
taxInclusiveAmount: 1210,
prepaidAmount: 0,
payableAmount: 1210,
},
invoiceLines: [
{
id: '1',
invoicedQuantity: 10,
unitCode: 'EA',
lineExtensionAmount: 1000,
price: 100,
name: 'Consulting Services',
currency: 'EUR',
taxCategory: { categoryCode: 'S', percent: 21 },
},
],
};
const xml: string = toolkit.invoiceToPeppolUBL(invoice);
console.log(xml);
import { PeppolToolkit, CreditNote } from '@pixeldrive/peppol-toolkit';
const toolkit = new PeppolToolkit();
const creditNote: CreditNote = {
ID: 'CN-2024-001',
issueDate: '2024-01-20',
creditNoteTypeCode: 381,
documentCurrencyCode: 'EUR',
buyerReference: 'PO-12345',
billingReference: {
invoiceDocReference: {
id: 'INV-2024-001',
issueDate: '2024-01-15',
},
},
seller: {
endPoint: { scheme: '9925', id: '0123456789' },
legalEntity: {
registrationName: 'Acme Corp',
companyId: '0123456789',
},
name: 'Acme Corp',
address: {
streetName: '123 Seller Street',
cityName: 'Brussels',
postalZone: '1000',
country: 'BE',
},
taxSchemeCompanyID: 'BE0123456789',
identification: [{ id: 'BE0123456789' }],
},
buyer: {
endPoint: { scheme: '9925', id: '9876543210' },
legalEntity: {
registrationName: 'Buyer Ltd',
companyId: '9876543210',
},
name: 'Buyer Ltd',
address: {
streetName: '456 Buyer Avenue',
cityName: 'Amsterdam',
postalZone: '1011',
country: 'NL',
},
taxSchemeCompanyID: 'NL9876543210',
identification: [{ id: 'NL9876543210' }],
},
taxTotal: [
{
taxAmountCurrency: 'EUR',
taxAmount: 21.0,
subTotals: [
{
taxableAmount: 100,
taxAmount: 21,
taxCategory: { categoryCode: 'S', percent: 21 },
},
],
},
],
legalMonetaryTotal: {
currency: 'EUR',
lineExtensionAmount: 100,
taxExclusiveAmount: 100,
taxInclusiveAmount: 121,
prepaidAmount: 0,
payableAmount: 121,
},
creditNoteLines: [
{
id: '1',
invoicedQuantity: 1,
unitCode: 'EA',
lineExtensionAmount: 100,
price: 100,
name: 'Consulting Services (correction)',
currency: 'EUR',
taxCategory: { categoryCode: 'S', percent: 21 },
},
],
};
const xml: string = toolkit.creditNoteToPeppolUBL(creditNote);
console.log(xml);
import { PeppolToolkit, Invoice, CreditNote } from '@pixeldrive/peppol-toolkit';
const toolkit = new PeppolToolkit();
// Parse an invoice XML string back into a structured Invoice object
const invoiceXml = '<?xml version="1.0"?>...'; // your UBL XML string
const invoice: Invoice = toolkit.peppolUBLToInvoice(invoiceXml);
console.log(invoice.ID); // 'INV-2024-001'
console.log(invoice.invoiceLines); // array of line items
// Parse a credit note XML string back into a CreditNote object
const creditNoteXml = '<?xml version="1.0"?>...'; // your UBL credit note XML
const creditNote: CreditNote = toolkit.peppolUBLToCreditNote(creditNoteXml);
console.log(creditNote.ID);
Use the static computeTotals helper to calculate line totals, tax amounts, and the grand total from a list of line items — following EN 16931 rounding rules.
import { PeppolToolkit } from '@pixeldrive/peppol-toolkit';
const items = [
{ price: 100, quantity: 10, taxPercent: 21 }, // 1 000.00 + 210.00 VAT
{ price: 49.99, quantity: 3, taxPercent: 21 }, // 149.97 + 31.49 VAT
{ price: 200, quantity: 2, taxPercent: 0 }, // 400.00 + 0.00 VAT (exempt)
];
const totals = PeppolToolkit.computeTotals(items);
console.log(totals.baseAmount.toNumber()); // 1549.97
console.log(totals.taxAmount.toNumber()); // 241.49
console.log(totals.totalAmount.toNumber()); // 1791.46
// Tax amounts grouped by rate
for (const [rate, taxableAmount] of totals.taxableAmountPerRate) {
console.log(`${rate}% → taxable: ${taxableAmount}`);
}
getEASFromTaxId resolves the correct EAS (Electronic Address Scheme) identifier for a given country-prefixed VAT number.
import { PeppolToolkit } from '@pixeldrive/peppol-toolkit';
const scheme = PeppolToolkit.getEASFromTaxId('BE0123456789');
console.log(scheme); // '9925'
const scheme2 = PeppolToolkit.getEASFromTaxId('NL9876543210');
console.log(scheme2); // '9944'
The toolkit ships ready-to-run example documents so you can test your integration without building a full document from scratch.
import {
PeppolToolkit,
exampleInvoice,
exampleCreditNote,
} from '@pixeldrive/peppol-toolkit';
const toolkit = new PeppolToolkit();
// Generate XML from the bundled example invoice
const invoiceXml = toolkit.invoiceToPeppolUBL(exampleInvoice);
console.log(invoiceXml);
// Generate XML from the bundled example credit note
const creditNoteXml = toolkit.creditNoteToPeppolUBL(exampleCreditNote);
console.log(creditNoteXml);
You can validate generated (or external) UBL XML through a running KoSIT validator service.
import { PeppolToolkit, exampleInvoice } from '@pixeldrive/peppol-toolkit';
const toolkit = new PeppolToolkit();
const xml = toolkit.invoiceToPeppolUBL(exampleInvoice);
const result = await toolkit.validateWithKosit(xml, {
endpoint: 'http://localhost:8081/',
});
console.log(result.valid); // true | false
console.log(result.errors); // validation errors
console.log(result.warnings); // validation warnings
Notes:
http://localhost:8081/.POST with Content-Type: application/xml.406 together with an XML report for invalid documents; this toolkit still parses that report and returns structured errors/warnings.PeppolToolkitThe main class that provides invoice and credit note conversion functionality.
| Method | Description |
|---|---|
invoiceToPeppolUBL(invoice: Invoice): string | Converts an Invoice object to a PEPPOL-compliant UBL XML string |
creditNoteToPeppolUBL(creditNote: CreditNote): string | Converts a CreditNote object to a PEPPOL-compliant UBL XML string |
peppolUBLToInvoice(xml: string): Invoice | Parses a PEPPOL UBL XML string into an Invoice object |
peppolUBLToCreditNote(xml: string): CreditNote | Parses a PEPPOL UBL XML string into a CreditNote object |
validateWithKosit(xml: string, options?: KositValidatorOptions): Promise<KositValidationResult> | Sends XML to a KoSIT validator service and returns parsed validation outcome |
| Helper | Description |
|---|---|
PeppolToolkit.computeTotals(items: UBLLineItem[]): Totals | Calculates line totals, tax amounts and grand total following EN 16931 rules |
PeppolToolkit.getEASFromTaxId(taxId: string): string | Returns the EAS scheme code for a country-prefixed VAT number |
createToolkit()Factory function that creates a new instance of PeppolToolkit. Equivalent to new PeppolToolkit().
import { createToolkit } from '@pixeldrive/peppol-toolkit';
const toolkit = createToolkit();
KositValidator and Related TypesAlso exported for direct use:
KositValidatorKositValidatorOptionsKositValidationResultKositValidationMessageThis toolkit supports the following PEPPOL BIS UBL invoice elements based on the current implementation:
⚠️ Early Development: This project is currently in early development. The Invoice type definitions and full feature set are still being implemented. Contributions and feedback are welcome!
Starting from version 1.0.0, this library will follow Semantic Versioning (SemVer). Until then, breaking changes may occur in minor and patch releases as the API is still being stabilized.
Last updated: 2026-03-31
npm run build - Build the librarynpm run dev - Build in watch mode for developmentnpm run test - Run testsnpm run lint - Lint the codebasenpm run format - Format code with PrettierPEPPOL is an international standard for electronic document exchange, particularly for invoicing and procurement. It ensures that electronic documents can be exchanged seamlessly between different systems across borders.
This toolkit helps you:
Contributions are welcome! This project is in active development and we're looking for contributors to help build out the full feature set.
Please feel free to:
MIT
This software is provided "as is" without warranty of any kind. Please ensure compliance with your local regulations and PEPPOL requirements when using this toolkit in production.
FAQs
A TypeScript toolkit for building and reading peppol UBL documents
We found that @pixeldrive/peppol-toolkit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.