KSeF integration: the mandatory e-invoicing timeline and connecting your own system to API 2.0
Blog
Technology

KSeF integration: the mandatory e-invoicing timeline and connecting your own system to API 2.0

Who issues e-invoices in KSeF and from when, what changes in the company, and how to integrate an online store, admin panel or ERP: authentication, sending and receiving invoices, limits, offline modes and QR codes

DualFroz - VulCode CEODualFroz - VulCode CEO·28 September 2026·23 min read

KSeF integration is needed by every company that issues invoices from its own system: an online store, an admin panel, an ERP or a billing application. KSeF is Krajowy System e-Faktur, Poland's National e-Invoicing System. Since 1 February 2026 all taxpayers receive invoices through it, since 1 April 2026 all companies issue them in it except those using the transitional period, and on 1 January 2027 the transitional period ends. A document sent to KSeF becomes an invoice only once it has been assigned a KSeF number, except in the statutory offline modes.

The first part of this article covers the timeline and the changes to day-to-day invoicing. The second is for teams connecting their own system: authentication in API 2.0, sending and receiving invoices, limits, and what the system has to be able to do when KSeF or the internet is down.

In short
  • Since 1 February 2026, invoices in KSeF have been issued by companies whose sales including VAT exceeded PLN 200 million in 2024, and since 1 April 2026 by everyone else. Receiving invoices through KSeF has applied to everyone since 1 February 2026.
  • Until 31 December 2026 you can issue invoices outside KSeF up to a total of PLN 10,000 gross per month, as well as invoices from cash registers.
  • Under current law, penalties for breaches are to apply from 1 January 2027. A draft act published on 23 September 2026 moves that date to 1 January 2028, but until it is passed, the date in the act applies.
  • Integrating with the KSeF API 2.0 covers authentication, encrypted sending of XML files in the FA(3) schema, retrieving the UPO and incremental synchronisation of purchase invoices.
  • The system has to handle offline modes: marking invoices, two QR codes, an offline KSeF certificate and sending invoices on within the statutory deadline.
i
Note

Status as of 28 September 2026. This article describes the regulations and technical documentation from the perspective of a software contractor and is not legal or tax advice. KSeF deadlines have already been moved, and the API documentation is updated regularly, so before you go live check the current announcements on ksef.podatki.gov.pl and the API changelog.

The KSeF timeline as of the end of September 2026

Mandatory KSeF was introduced by the Act of 5 August 2025 amending the VAT Act (Journal of Laws, item 1203), which set the current deadlines. As of publication they look like this:

Key dates

DateWhat happens
1 February 2026Obligation to issue invoices in KSeF for companies whose sales including VAT exceeded PLN 200 million in 2024. Obligation for everyone to receive invoices through KSeF. The FA(3) schema applies from this date
1 April 2026Obligation to issue invoices in KSeF for all other taxpayers
until 31 December 2026Outside KSeF you can issue invoices up to a total value of PLN 10,000 gross per month, invoices from cash registers and receipts treated as simplified invoices
1 January 2027End of the transitional period. KSeF number in the transfer title between active VAT taxpayers. Under current law, penalties start to apply

The PLN 10,000 limit in Article 145m of the amending act works per invoice: a taxpayer loses the right to issue invoices outside KSeF starting with the invoice that took it over the monthly threshold. Invoices from cash registers and receipts up to PLN 450 treated as simplified invoices do not count towards the limit, which the Ministry of Finance confirms in its questions and answers on KSeF 2.0.

Penalties are set out in Article 106ni of the VAT Act. For issuing an invoice outside KSeF contrary to the obligation, or for failing to send an offline invoice on time, the head of the tax office imposes a penalty of up to 100% of the VAT amount on that invoice, and where the invoice shows no tax, up to 18.7% of the total amount due. Under current law these apply from 1 January 2027.

On 16 September 2026 the Ministry of Finance announced that it wants to extend the penalty-free period to 31 December 2027. The ministry stresses that deferring penalties does not mean there is no obligation to use KSeF, and that the National Revenue Administration will respond to invoices being issued outside the system. On 23 September 2026 a draft act (UD477) was published by the Government Legislation Centre, under which the penalty provisions of Article 106ni would enter into force on 1 January 2028. At the time of publication of this article the draft is at the interministerial agreement and consultation stage, so the deadline in the act applies.

What KSeF changes in the company

A structured invoice is an XML file conforming to the FA(3) schema and sent to KSeF. Once accepted, it receives a KSeF number: 35 characters made up of the seller's NIP (the Polish tax identification number), the date of acceptance, a technical part and a checksum. The invoice is deemed received by the buyer at the moment the number is assigned, with no acceptance on the buyer's part. That date is confirmed by the Official Receipt Confirmation (Urzędowe Poświadczenie Odbioru, UPO). KSeF stores invoices for 10 years, counting from the end of the year in which they were issued.

A few consequences that affect company processes:

  • KSeF is not a reporting system. You do not issue an invoice in your software and "report" it later. You issue it using KSeF, and a file that has not received a number is not an invoice.
  • Invoices for consumers are voluntary in KSeF. If the seller does issue them there, it delivers them to the consumer in an agreed way, for example as a PDF with a QR code.
  • A foreign buyer without a Polish NIP cannot log in to KSeF. The invoice is issued in KSeF and delivered to the buyer through an agreed channel with a QR code.
  • Corrections only to an invoice with a number. A corrective invoice can be sent only after the original invoice has been assigned a KSeF number. An invoice accepted by KSeF cannot be changed; errors are fixed with a corrective invoice.
  • Attachments require prior notice. Invoices with an attachment can be issued after submitting a notice in the e-Tax Office (e-Urząd Skarbowy), only in software integrated with the API and only in a batch session. The maximum size of such an invoice is 3 MB.
  • Access is granted through permissions. A company that is not a natural person and does not have a qualified electronic seal submits a ZAW-FA notification naming the person who will handle KSeF, and that person grants permissions to other people and systems.

The ministry also lists benefits, including faster VAT refunds: in 40 days instead of 60.

Four ways into KSeF

Not every company needs its own integration. The choice depends on where invoices are created and how many there are.

Ways of using KSeF

ToolFor whom
KSeF Taxpayer Application (Aplikacja Podatnika KSeF) and the mobile app, free Ministry of Finance toolsA few invoices a month issued by hand
e-mikrofirma in the e-Tax OfficeThe smallest businesses that want invoices straight in their VAT records
Accounting or invoicing software integrated with KSeFCompanies that already issue invoices in such software
Your own integration through the APIAn online store, admin panel, ERP or billing system that generates invoices itself

If invoices are created in a store or panel, there are two routes. You can pass order data to invoicing software that has a KSeF integration, or build sending to KSeF directly into your own system. The first is quicker to launch. The second gives full control over statuses and error handling, but FA(3) schema compliance, offline modes and QR codes then become your system's job.

For building an integration, the Ministry of Finance provides the KSeF API 2.0 documentation with an OpenAPI specification and two open source libraries: one for Java and one for C#. For other languages, the specification is enough to write your own client.

Authentication: context, KSeF certificate and token

Every protected API call requires a JWT access token. To obtain one, the system specifies the context, meaning the entity on whose behalf it acts (usually the company's NIP), and proves the identity of the authenticating entity, which must hold an active permission in that context.

The authentication documentation describes two methods. The first is an AuthTokenRequest XML document signed in XAdES format: with a qualified signature, a qualified seal, a trusted profile signature (podpis zaufany, the Polish government e-identity signature) or a KSeF certificate. The second is a KSeF token generated earlier in the system. The flow looks like this:

1
Challenge

POST /auth/challenge returns a challenge value and a timestamp. The challenge is valid for 10 minutes.

2
Signature or token

in the signature variant, the system sends the signed AuthTokenRequest to POST /auth/xades-signature. In the token variant, it encrypts the string token|timestampInMilliseconds with the KSeF public key using RSA-OAEP with SHA-256 and sends it to POST /auth/ksef-token.

3
Status

the response contains a temporary operation token and a reference number. The system polls GET /auth/{referenceNumber} until authentication is complete. In the pre-production and production environments, KSeF also checks the certificate's status with its issuer, which can take a while.

4
Access tokens

POST /auth/token/redeem returns a pair, once: a short-lived accessToken and a refreshToken valid for up to 7 days.

5
Refresh

POST /auth/token/refresh with the refresh token returns a new access token without authenticating again.

A few design decisions worth making straight away:

  • A KSeF certificate in production. The documentation recommends authenticating with a KSeF certificate, because it is verified inside the system, without waiting for a response from an external qualified certificate provider. There are two types of certificate: one for authentication and one for offline mode. Each is valid for at most 2 years, so rotation has to be planned.
  • Tokens. Tokens from KSeF 1.0 do not work in KSeF 2.0, and new ones can be generated from 1 February 2026. The regulations provided for this method to expire at the end of 2026, but the Ministry of Finance decided that tokens will remain available indefinitely and announced an amendment to the regulation.
  • Secrets outside the code. The certificate's private key, the KSeF token and the refresh token are stored in a secrets vault or in the server's environment variables, never in the repository.
  • IP address list. The authentication request can include an authorisation policy with a list of allowed IP addresses from which the issued access token may be used.
  • Permissions sized to the task. Sending invoices requires the InvoiceWrite permission. The system's technical account does not need permission to manage other people's permissions.

Sending invoices: interactive or batch session

Invoices are sent in sessions. Each XML file is encrypted with AES-256-CBC with PKCS#7 padding, using a 256-bit symmetric key and a 128-bit initialisation vector. The symmetric key is encrypted with RSA-OAEP with SHA-256 using the Ministry of Finance public key, which the system fetches from GET /security/public-key-certificates. The documentation recommends a new key for each session.

An interactive session is for sending individual invoices. You open it with POST /sessions/online, providing the form code (for FA(3): systemCode "FA (3)", schemaVersion "1-0E", value "FA") and the encrypted key. A session is valid for 12 hours, and you can have several open sessions under one authentication. You send an invoice to POST /sessions/online/{referenceNumber}/invoices together with SHA-256 hashes and the file sizes before and after encryption. Verification is asynchronous: the invoice status and UPO are retrieved with separate calls, and closing the session triggers generation of a collective UPO.

Preparing the request body in Node.js looks like this (the certificate is the value of the certificate field for the key intended for SymmetricKeyEncryption):

ksef-encryption.mjs · javascript
import {
  X509Certificate, constants, createCipheriv, createHash, publicEncrypt, randomBytes,
} from 'node:crypto';

const sha256 = (data) => createHash('sha256').update(data).digest('base64');

export function prepareSessionKey(certificateBase64) {
  const certificate = new X509Certificate(Buffer.from(certificateBase64, 'base64'));
  const key = randomBytes(32);
  const iv = randomBytes(16);
  const encryptedKey = publicEncrypt(
    { key: certificate.publicKey, padding: constants.RSA_PKCS1_OAEP_PADDING, oaepHash: 'sha256' },
    key,
  );
  return {
    key,
    iv,
    encryption: {
      encryptedSymmetricKey: encryptedKey.toString('base64'),
      initializationVector: iv.toString('base64'),
    },
  };
}

export function buildSendInvoiceBody(invoiceXml, key, iv, offlineMode = false) {
  const cipher = createCipheriv('aes-256-cbc', key, iv);
  const encrypted = Buffer.concat([cipher.update(invoiceXml), cipher.final()]);
  return {
    invoiceHash: sha256(invoiceXml),
    invoiceSize: invoiceXml.length,
    encryptedInvoiceHash: sha256(encrypted),
    encryptedInvoiceSize: encrypted.length,
    encryptedInvoiceContent: encrypted.toString('base64'),
    offlineMode,
  };
}

invoiceXml is a buffer with exactly the bytes that will reach KSeF, in UTF-8 without a BOM. A hash of a different version of the file, for example after the XML has been reformatted, will not match the content.

A batch session is for sending many invoices at once. The XML files are packed into a ZIP archive, which is split binary-wise into parts of up to 100 MB before encryption, with at most 50 parts and 5 GB in total. Each part is encrypted separately, and uploading parts is not subject to request limits, so they can be sent in parallel.

Default limits according to the September 2026 documentation

ParameterValue
Invoice size without / with attachment1 MB / 3 MB
Number of invoices in one session10,000
Sending an invoice in an interactive session10 per second, 30 per minute, 180 per hour
Opening an interactive / batch session120 / 60 per hour
Exporting a package of purchase invoices20 per hour

Request limits are counted separately for each pair of context and IP address, in a sliding time window. When a limit is exceeded, the API returns a 429 code with a Retry-After header, and repeated breaches extend the block. The documentation notes that the limits are dynamic and may change.

For an online store this matters directly. The limit of 180 invoices per hour in interactive mode is easy to exceed on a sale day. In its limits documentation, the ministry explicitly describes an e-commerce scenario: invoices do not have to reach KSeF immediately after being issued, and a separate process can collect them and send them as a package in a batch session every few minutes. Interactive mode is kept for situations where the KSeF number is needed straight away, for example at a point of sale. Just remember that an invoice issued as online must reach KSeF on the same day, otherwise the system will treat it as issued in offline24 mode.

Validation: before KSeF rejects an invoice

Invoice verification in KSeF covers XML 1.0 validity, UTF-8 encoding without a BOM, conformity with the schema declared when the session was opened, and the absence of processing instructions and disallowed characters. The issue date in the P_1 field cannot be later than the date of acceptance into KSeF, and in production the NIP checksums are verified.

KSeF detects duplicates globally, based on the seller's NIP, the invoice type and the invoice number in the P_2 field, and rejects them with code 440. Uniqueness applies for 10 years. If several systems or branches issue invoices on behalf of one company, they must have coordinated numbering.

What KSeF does not check matters too. According to the Ministry of Finance, the system does not verify arithmetic correctness or the counterparty's details. An invoice with the wrong buyer NIP will be accepted and will be visible to the entity with that number, and fixing it requires a corrective invoice down to zero and a new invoice. A file rejected by KSeF is not an invoice, so you do not correct it; you send a new, valid XML.

This leads to three implementation rules:

  • Local validation before sending. The file is checked against the FA(3) XSD schema and the business rules, including the buyer's NIP checksum, before it goes into the queue.
  • A queue instead of sending within the user's request. The invoice goes into a queue table, and a separate process sends it to KSeF, retrieves the status and saves the KSeF number and UPO with the invoice. The store customer does not wait for KSeF to respond.
  • The hash as an idempotency key. The system stores the SHA-256 hash of every file sent. After a dropped connection it first checks the list of invoices sent in the session in KSeF, and only then decides whether to send again.

Receiving purchase invoices: synchronisation, not browsing

The API for downloading invoices was designed as a mechanism for synchronising with a local database, not for serving users in real time. The documentation explicitly advises against fetching an invoice from KSeF in response to a user's click: searching, filtering and previewing should work on data that has already been synchronised.

The recommended mechanism is incremental download through package exports (POST /invoices/exports). The export runs asynchronously: the system requests it with an encryption key, polls the status, downloads the encrypted parts of the ZIP archive, decrypts them and unpacks the XML files together with the _metadata.json file. Successive time windows should be adjacent and based on the date of permanent storage in KSeF, using a High Water Mark mechanism. When a package is truncated by the limit on the number of invoices or size, the next window starts from the date of the last invoice in the package. Duplicates are removed using the KSeF numbers from the metadata.

Invoices are downloaded separately for each role the company can have on an invoice: buyer, seller, third party and authorised entity. The synchronisation interval should not be shorter than 15 minutes for each role, and higher download limits apply from 20:00 to 06:00.

One point concerns accounting rather than code: the date an invoice is received is the date its KSeF number was assigned, regardless of when your system downloads it. If you calculate a payment deadline or settlement period from the date of receipt, take it from the KSeF metadata, not from the import date.

Offline modes and outages

The act provides for several situations in which an invoice is issued without a connection to KSeF and sent on later. The offline modes documentation sets them out as follows:

Modes for issuing outside KSeF

ModeWhenDeadline for sending to KSeF
offline24For any reason, for example no internetNo later than the next business day after the day of issue
offline (unavailability)Maintenance announced by the Ministry of FinanceThe next business day after the unavailability ends
emergencyA failure announced in the Ministry of Finance's Public Information Bulletin (BIP) and in the interface software7 business days from the end of the failure, restarting with each new announcement
total failureAnnounced in the mass mediaNot sent; paper or electronic invoice, without QR codes

The issue date of an offline invoice is the date in the P_1 field. When sending such an invoice, you set offlineMode: true. If the buyer receives the invoice before it has been sent to KSeF, the visualisation must have two QR codes: the first labelled "OFFLINE", which allows the invoice to be verified, and the second labelled "CERTYFIKAT" (Polish for "certificate"), which confirms the issuer's identity. Generating the second code requires an offline-type KSeF certificate, which you need to have before the first outage, not order during it. An authentication certificate cannot be used for this.

If an offline invoice that has been sent on is rejected for technical reasons, for example a schema error or the file size, the documentation provides for a technical correction: resending an invoice with the same content in a valid form, only in an interactive session. A technical correction is not for changing the content of the invoice.

For the system this means specific features: detecting a lost connection, offline invoices with two QR codes, a send-on queue with deadlines in business days, and an alert when a deadline is approaching.

QR codes on invoices delivered outside KSeF

QR codes are needed wherever an invoice reaches the recipient other than by being downloaded from KSeF: as a PDF in an email, a printout for a consumer, an invoice for a foreign buyer. They are generated locally by the system issuing the invoice, in line with ISO/IEC 18004:2024.

The first code contains a URL with the seller's NIP, the issue date from the P_1 field in DD-MM-YYYY format and the SHA-256 hash of the invoice file in Base64URL format. Under the code of an invoice accepted by KSeF, you place its KSeF number.

ksef-qr.mjs · javascript
import { createHash } from 'node:crypto';

export function invoiceVerificationUrl(sellerNip, issueDate, invoiceXml) {
  const [year, month, day] = issueDate.split('-');
  const hash = createHash('sha256').update(invoiceXml).digest('base64url');
  return `https://qr.ksef.mf.gov.pl/invoice/${sellerNip}/${day}-${month}-${year}/${hash}`;
}

In the test environments, the addresses qr-test.ksef.mf.gov.pl and qr-demo.ksef.mf.gov.pl are used instead of qr.ksef.mf.gov.pl. After scanning the code, anyone can check whether the invoice is in KSeF and whether it has been altered.

The KSeF number in payments from 2027

From 1 January 2027, an active VAT taxpayer who pays another active VAT taxpayer for a structured invoice by bank transfer or direct debit must include in the payment title the invoice's KSeF number or a collective identifier assigned by KSeF (Article 108g of the VAT Act). From the same date, the KSeF number is also mandatory in transfers made under the split payment mechanism.

For systems, this means the KSeF number must be stored with every purchase invoice and go into the payment file or the bank integration. According to the documentation, one collective identifier can cover up to 500 invoices.

Environments and testing before production

KSeF 2.0 has three public environments: test (TEST) with release candidates, pre-production (DEMO) with production configuration, and production (PROD). Self-signed certificates are allowed in the test environment, so data is not isolated from other integrators, and you should use random NIPs, never real data. Limits there are ten times higher than in production, and separate calls let you switch production limits on. Since 1 October 2025, maintenance may take place in the test environments from 16:00 to 18:00.

Before going live in production, it is worth running at least these scenarios:

  • sending a valid invoice, retrieving the status and UPO,
  • an invoice with a schema error and a duplicate number,
  • exceeding the request limit and handling the Retry-After header correctly,
  • the access token expiring mid-work and being refreshed,
  • an offline24 invoice with two QR codes and sending it on, including with a technical correction,
  • synchronising purchase invoices with a truncated package and duplicate removal,
  • a change of the Ministry of Finance public key, which the documentation describes as a planned rotation scenario.

KSeF integration plan, step by step

1
List of invoice sources

store, panel, ERP, manual invoices in the office.

2
Choosing the route

your own integration or passing data to invoicing software integrated with KSeF.

3
Access and permissions

ZAW-FA notification or a qualified seal, a technical account with permission to issue invoices, certificates for authentication and for offline mode, a secrets vault.

4
Mapping data to FA(3)

every type of invoice you issue, including corrections and advance invoices, with validation against the schema.

5
Sending

queue, sessions, statuses, KSeF number and UPO saved with the invoice.

6
Receiving

incremental synchronisation of purchase invoices into your own database.

7
Offline modes and visualisations

PDF with QR codes, a send-on queue with deadlines in business days.

8
Payments

KSeF number in bank transfers from 2027.

9
Testing on TEST and DEMO

the scenarios from the previous section.

10
Monitoring

alerts for invoices waiting too long, for 4xx and 5xx errors from the API and for expiring certificates.

An alert has to reach someone who can act before the statutory deadline passes. We described how to set up monitoring in our article on monitoring and maintenance after launch. If invoices are created in a spreadsheet today and the integration is meant to be part of a larger panel, also read about when an admin panel replaces a spreadsheet.

Online stores and KSeF

In a store, most decisions concern how customers are split. Invoices for consumers do not have to go to KSeF, but when a customer provides a NIP and buys as a business, the invoice must be issued in KSeF (until the end of 2026, subject to the exceptions described above), and the customer can download it from the system. So the store should distinguish business and consumer orders already in the cart.

Store customers still expect an email with a PDF, so the visualisation should include the QR code and the KSeF number. The details on invoices for sole traders are personal data, so processing them is subject to the rules described in our article on a GDPR compliant website. If you are still choosing a sales channel, you will find a comparison of your own store and a marketplace in Your own online store or Allegro.

Frequently asked questions

When does KSeF become mandatory?

From 1 February 2026 for companies whose sales including VAT exceeded PLN 200 million in 2024, and from 1 April 2026 for everyone else. Receiving invoices through KSeF has applied to everyone since 1 February 2026.

Does a small business have to use KSeF in 2026?

Until 31 December 2026 it can issue invoices outside KSeF if their total gross value in a month does not exceed PLN 10,000. From the invoice that takes it over that threshold, it must use KSeF. From 1 January 2027 the exception no longer applies.

Do invoices for consumers have to be issued in KSeF?

No, issuing invoices for consumers in KSeF is voluntary. If the seller does issue them there, it delivers the invoice to the consumer in an agreed way, with a QR code.

Will the KSeF token stop working at the end of 2026?

According to the Ministry of Finance, no. The ministry decided to keep tokens as an authentication method indefinitely and announced an amendment to the regulation. Tokens generated in KSeF 1.0 do not work in KSeF 2.0.

What should you do when KSeF is down?

For maintenance, the invoice is sent on the next business day after it ends; for a failure announced by the Ministry of Finance, within 7 business days of its end; and for a total failure, not at all. Regardless of the state of KSeF, you can also issue an invoice in offline24 mode and send it no later than the next business day.

Will penalties for KSeF errors apply from 2027?

Under current law, yes, from 1 January 2027. The draft act published on 23 September 2026 (UD477) moves that date to 1 January 2028, but until it is passed, the date in the act applies.

An integration that survives an outage and a tax inspection

A KSeF integration is several processes: a sending queue, purchase invoice synchronisation, offline modes, QR codes and deadline monitoring. They are cheapest to design together, before the first invoice gets stuck in the queue on the day of an outage.

If your store, panel or ERP needs to send invoices to KSeF and you want to discuss the scope of such an integration, get in touch through the contact form. We describe our integration projects on the Integrations & Automation page, and how we work on the process page. After handover you get full rights to the code and documentation, so your own team can continue developing the integration too.