nordinvoice
v0.2.0
Published
Official Node.js SDK for the NordInvoice API: validate, generate and deliver Peppol e-invoices from your own product.
Maintainers
Readme
nordinvoice
Official Node.js SDK for the NordInvoice API: validate, generate and deliver Peppol e-invoices from your own product. No UBL. No Schematron. No compliance team.
- Full TypeScript types for every request and response
- Typed errors (
RateLimitedError,PaymentRequiredError, …) with the API's machine-readable codes - Automatic retry on rate limits, honouring
Retry-After - Zero runtime dependencies; Node 18+
Install
npm install nordinvoiceYour first invoice in five minutes
Get a free sandbox key at nordinvoice.com/register — the dashboard creates a working nord_test_ key in seconds.
import { NordInvoice } from 'nordinvoice'
const nord = new NordInvoice({ apiKey: 'nord_test_…' })
const result = await nord.invoices.create({
invoiceNumber: 'INV-2026-001',
issueDate: '2026-08-06',
dueDate: '2026-09-05',
currency: 'EUR',
buyerReference: 'PO-2026-001',
seller: {
name: 'Demo Supplier BV', street: 'Keizersgracht 1', city: 'Amsterdam',
postalCode: '1015 CC', countryCode: 'NL', vatNumber: 'NL123456789B01',
electronicAddress: '12345678', electronicAddressScheme: '0106',
},
buyer: {
name: 'Demo Buyer GmbH', street: 'Unter den Linden 5', city: 'Berlin',
postalCode: '10117', countryCode: 'DE', vatNumber: 'DE123456789',
electronicAddress: '991234567', electronicAddressScheme: '0204',
},
paymentIban: 'NL91ABNA0417164300',
lines: [{ description: 'Consultancy', quantity: 10, unitCode: 'C62', unitPrice: 100, vatPercent: 21 }],
}, { send: true })
console.log(result.readyToSend) // true: the draft passed the full rule set
console.log(result.job?.id) // delivery queued; poll nord.jobs.get(id)Sandbox keys deliver to a simulated network, so you can integrate end to end before anything real leaves the building.
What else it does
// Validate your own UBL/CII XML (or a ZUGFeRD PDF) against any of 11 rule sets
const outcome = await nord.validate.file(
{ content: xml, filename: 'invoice.xml' }, 'xrechnung-invoice')
// Read an invoice PDF or photo into structured data (AI extraction)
const fields = await nord.extract({ content: pdfBytes, filename: 'scan.pdf' })
// Generate UBL without sending or charging — credit notes included
const cn = await nord.generate(draft, 'peppol-creditnote')
// Bulk delivery: up to 25 files per call
const job = await nord.jobs.send(files)
// Sending history, filterable and paged
const rows = await nord.shipments.list({ status: 'DELIVERED', month: '2026-08' })
// Is my customer on Peppol?
const check = await nord.participants.verify('0106:12345678')
// EU VAT number check against VIES
const vat = await nord.vat('NL', '123456789B01')
// Receiving: register once, then read your inbox
await nord.receiving.register({ name: '…', address: '…', postalCode: '…', city: '…', country: 'NL' })
const inbox = await nord.receiving.inbox()
// Signed webhooks for delivery events
const hook = await nord.webhooks.create('https://your-app.example/webhooks/nordinvoice')Errors
Every non-2xx answer raises a typed error carrying the HTTP status and the API's error code:
import { PaymentRequiredError, RateLimitedError } from 'nordinvoice'
try {
await nord.invoices.create(draft, { send: true })
} catch (error) {
if (error instanceof PaymentRequiredError) {
// monthly quota exhausted, or live sending needs a subscription/credits
} else if (error instanceof RateLimitedError) {
console.log('retry in', error.retryAfterSeconds, 's')
}
}Rate-limited requests are retried automatically (twice by default, waiting out Retry-After); tune with maxRetries.
Options
new NordInvoice({
apiKey: 'nord_live_…', // required
baseUrl: 'https://nordinvoice.com', // default
language: 'de', // error messages in en, de or nl
timeoutMs: 60_000,
maxRetries: 2,
})Documentation
Full API reference and a live console for every endpoint: docs.nordinvoice.com
License
MIT
