Integration guide

KSeF API Node.js integration guide

Send a KSeF FA(3) invoice from Node.js with the Notaly API: POST /invoices, idempotency, error handling and status tracking.

Updated

Overview

Node.js is the quickest way to get your first KSeF invoice into the Polish e-invoicing system through Notaly. You describe the invoice as plain JSON, send it in one POST request, and Notaly takes care of the rest: it generates the FA(3) XML, validates it against the official schema and submits it to KSeF. This page gives you a complete, runnable example using the global fetch that has shipped with Node.js since version 18, so there is nothing to install.

Before you start

Create a free sandbox account and copy your API key from the dashboard. Two details matter in the sandbox. First, the seller NIP is fixed to 2745013933, the test NIP bound to Notaly's test certificate; sending a different seller NIP returns 422 seller_nip_not_authorized before the invoice reaches KSeF and before your three free test invoices are consumed. Second, the Idempotency-Key header is how you make retries safe: resending the same key returns the same invoice instead of a duplicate.

Send the invoice

const NOTALY_API_KEY = process.env.NOTALY_API_KEY;

const invoice = {
  number: "FV/2026/10/001",
  issueDate: "2026-10-12",
  currency: "PLN",
  seller: { nip: "2745013933", name: "Example Sp. z o.o. (FICTIONAL)", address: { line1: "ul. Testowa 1, 00-001 Warszawa", country: "PL" } },
  buyer: { nip: "1234563218", name: "Test Customer S.A. (FICTIONAL)", address: { line1: "ul. Probna 2, 30-001 Kraków", country: "PL" } },
  items: [
    { name: "SaaS subscription - October", unit: "pcs.", quantity: 1, unitNetPrice: 1000, vatRate: 23 },
    { name: "Support", unit: "hrs.", quantity: 2, unitNetPrice: 150.5, vatRate: 8 }
  ]
};

const response = await fetch("https://api.getnotaly.com/invoices", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${NOTALY_API_KEY}`,
    "Content-Type": "application/json",
    "Idempotency-Key": crypto.randomUUID()
  },
  body: JSON.stringify(invoice)
});

if (!response.ok) {
  const body = await response.json();
  console.error(`${response.status}:`, body.error, body.details ?? body.message ?? "");
  process.exit(1);
}

const created = await response.json();
console.log(`Invoice ${created.id} is ${created.status}`);

Read the response

A successful call returns HTTP 201 with the invoice object. The most important field is status. It is submitted when KSeF has accepted the submission, or draft when KSeF was temporarily unavailable and the invoice was saved so you can retry later. The response also carries id (use it to fetch status), ksefReferenceNumber, and, once the invoice is accepted, upo and pdfUrl. Notaly validates and submits the invoice; VAT rates and tax classification remain your responsibility.

Handle the common errors

Notaly returns structured errors you can branch on. A 422 validation_failed includes a details array telling you exactly which field is wrong. 402 quota_exceeded means you have used your three free sandbox invoices. 401 means the API key is missing or invalid and 404 means the key is valid but the resource is not yours. A 503 ksef_unavailable is transient; retry with backoff.

Track the result

const res = await fetch(`https://api.getnotaly.com/invoices/${created.id}`, {
  headers: { Authorization: `Bearer ${NOTALY_API_KEY}` }
});
const invoice = await res.json();
console.log(invoice.status); // draft | submitted | accepted | rejected

The lifecycle is draft → submitted → accepted or rejected. You can poll GET /invoices/:id, or subscribe to webhooks so Notaly pushes each status change to your endpoint with a signed header.

Sources

Source: getnotaly.com

Frequently asked questions

Which Node.js version do I need?

Node.js 18 or newer, because the example uses the built-in global fetch. Older versions can use node-fetch or axios instead.

Can I send multiple items per invoice?

Yes. The items array accepts up to 1,000 line items, each with name, quantity, unit net price and VAT rate.

Issue your first KSeF test invoice today

Create a sandbox account: API key in seconds, 3 free test invoices on KSeF TEST, no credit card.