KSeF 2.0 integration — how to connect your own system to the e-invoicing API

A practical guide to integrating with Poland's KSeF 2.0 e-invoicing API: authentication, sessions, the FA schema, status polling, UPO handling, idempotency and fallback modes — plus a rollout plan before the penalty-free period ends.

Zespół Mobilesoft· Engineering team· 14 września 2026· 8 min czytania

KSeF 2.0 integration — how to connect your own system to the e-invoicing API

Poland's National e-Invoicing System (KSeF) has stopped being a "later" topic. The obligation to issue structured invoices covered large taxpayers from 1 February 2026, all other companies from 1 April 2026, and micro-enterprises with turnover up to PLN 10,000 per month only from 1 January 2027. A transitional period runs until the end of 2026, during which the tax authorities do not impose penalties — but once it ends, sanctions can reach as much as 100% of the tax amount shown on an invoice issued outside the system.

In other words: if you build or maintain an ERP, an invoicing system or a backend that handles sales, you still have a few months of real margin to complete your integration with the KSeF 2.0 API. This article is a practical guide to the integration architecture: what you need to understand, what the invoice submission flow looks like, and what is easy to forget in a production rollout.

Note: the text below describes the logic and architecture of the integration at a high level. Specific endpoint names, fields and schemas change between versions — always verify the details in the official documentation of the Ministry of Finance (ksef.gov.pl and the API and schema repository). Never code an integration from memory or from blog articles.

What KSeF is from a technical standpoint

From a developer's perspective KSeF is a central state platform that:

  • accepts structured invoices in XML conforming to a mandated schema (FA(2), eventually FA(3)),
  • validates them against the XSD schema and business rules,
  • assigns each invoice a unique KSeF number and an acceptance date (that moment is the issue date in legal terms),
  • returns a UPO — the official acknowledgement of receipt, i.e. proof that the invoice was successfully accepted,
  • makes invoices available that were issued to a given taxpayer (you are both an issuer and a recipient of e-invoices).

Your system does not "send a PDF to the customer". Your system talks to a state API, and the invoice circulates inside KSeF. That is a mental model shift that has to be reflected in your architecture.

Environments

The Ministry of Finance provides separate environments. In practice you run the integration on the test / pre-production environment (for development and acceptance testing, with no legal effects) and only switch to production after verification. Each environment has its own API base address and its own pool of tokens and certificates — never mix credentials between them.

Key concepts you cannot start without

  • KSeF number — the identifier assigned to an invoice by the system after successful validation. Only once you receive it does the invoice "exist".
  • UPO — the official confirmation of acceptance (for a batch session it is issued for the whole package). It is a document you are required to store.
  • Session — communication with KSeF happens within a session. You open it, send one or many invoices, and close it at the end, which triggers the issuance of the UPO.
  • Interactive vs batch session — the interactive one suits sending single invoices as they occur; the batch one serves large packages sent in one go (e.g. a nightly export from an ERP).
  • The FA schema — the XSD defining the invoice structure. Mapping data from your model onto the schema fields is usually the most labour-intensive part of the rollout.
  • Permissions — access to issuing/receiving invoices on behalf of an entity follows a permission model (owner, permissions granted to an employee, system access via token/certificate).

Authentication in KSeF 2.0

This is the most common flashpoint of the integration. In KSeF 2.0 system authentication is based on cryptographic credentials — a KSeF certificate and/or a token tied to the permissions of a given entity. The simplified flow looks like this:

  1. Obtain a challenge from the API for a specific tax ID (NIP) / entity.
  2. Sign the authentication request — with a qualified signature, a qualified seal, or a KSeF token/certificate granted to the system.
  3. Receive a session (access) token that authorises subsequent calls within the session.
# Schematically (pseudo-flow, field names depend on the API version):

POST /auth/challenge          -> { challenge, timestamp }
   sign the payload (certificate / token)
POST /auth/token   (signed)   -> { sessionToken, expiresIn }
   header on subsequent requests: Authorization: Bearer <sessionToken>

Practical architectural conclusions:

  • Tokens are short-lived — design refreshing and secure storage (secret manager / vault, never in the repo).
  • Certificates and private keys belong in a KMS/HSM, or at minimum in an encrypted secrets store.
  • Multi-tenancy — if you serve many clients (e.g. a SaaS ERP), you need credential isolation per tax ID and a permission-granting model.

The invoice submission flow step by step

The target "happy path" for a single invoice looks as follows:

  1. Generate the invoice XML conforming to the FA schema and validate it locally against the XSD (client-side validation saves a great many round trips).
  2. Authenticate and open a session.
  3. Send the invoice into the session. In response you usually get a reference identifier (element reference number) rather than the KSeF number straight away.
  4. Poll for status — validation is often asynchronous. The status moves from "accepted for processing" to "accepted" (with a KSeF number) or "rejected" (with a list of errors).
  5. Close the session — this triggers generation of the UPO.
  6. Download and archive the UPO together with the KSeF number stored against the invoice in your database.
# Simplified lifecycle (pseudo-code):

session = openSession(sessionToken)
ref     = session.sendInvoice(invoiceXml)

status = poll(ref, until = ["ACCEPTED", "REJECTED"], backoff = expo)
if status == ACCEPTED:
    ksefNumber = status.ksefReferenceNumber
    persist(invoiceId, ksefNumber, status)
else:
    handleValidationErrors(status.errors)

session.close()          # generates the UPO
upo = session.fetchUPO() # archive it (a legal retention obligation)

What the happy path hides — and what will wreck your rollout

Idempotency and deduplication. The network can drop the connection after an invoice has been sent but before the response arrives. Without an idempotency key and hard deduplication on your side you risk issuing the same invoice twice in KSeF — and that is an accounting problem, not a technical one.

Asynchronicity. Treat submission as a process, not a synchronous INSERT. A queue (e.g. the outbox pattern), a worker with retries and exponential backoff, and an "in progress / accepted / rejected" state per invoice are the minimum.

Local validation. Validate the XML against the XSD before sending. Separately, enforce business rules (tax IDs, totals, currencies, VAT rates), because some rejections stem not from the schema but from the system's rules.

Storing UPOs and KSeF numbers. These are data you must archive and be able to reproduce. Design an invoice ↔ KSeF number ↔ UPO ↔ status mapping from day one.

Handling KSeF outages. A state system has maintenance windows and downtime. The regulations provide for offline/emergency modes with later submission — your backend must be able to queue and resend rather than block sales.

Limits and throughput. At high volume, consider batch sessions instead of hundreds of individual calls. Design throttling and monitor response times.

How to plug this into an existing ERP / backend

The proven pattern is an intermediate layer (a KSeF adapter) separated from the ERP logic:

  • Mapper — translates your invoice model into FA XML (and back, for incoming invoices). This is the heart of the integration; encapsulate it and cover it with tests based on real examples.
  • Outbox + queue — once approved in the ERP, an invoice lands in an outbox table; a worker sends it to KSeF asynchronously and updates the status. Sales do not wait for the state.
  • KSeF client — a thin library handling auth, sessions, submission, polling and UPOs, with retries and idempotency.
  • Credential and evidence store — UPOs, KSeF numbers, request/response logs (useful for complaints and audits).
  • Operations panel — a view of rejected invoices with the reason for the error and the ability to retry. Without it, your accounting team will drown in invisible failures.

An implementation plan for the coming months

Realistically you have a few months until the transitional period ends. A sensible order:

  1. Registration and permissions — arrange system access to the test environment, generate tokens/certificates, sort out the permission model per entity.
  2. Data mapping — map your invoice model onto the FA schema. Collect the "hard" cases: corrections, advance invoices, foreign currencies, reverse charge, complex rates.
  3. Client and flow — implement auth, sessions, submission, polling, UPOs. Add idempotency and retries.
  4. Testing on pre-production — push real volume and error scenarios through it (rejections, timeouts, a KSeF outage).
  5. Archiving and reporting — UPOs, KSeF numbers, statuses, a panel for accounting.
  6. Cutover to production — first in parallel/pilot mode, then the full rollout. Plan monitoring and alerts.

Summary

Integrating with KSeF 2.0 is not "adding one endpoint". It means designing a resilient, asynchronous flow: cryptographic authentication, sessions, validation against the FA schema, status polling, UPO handling, idempotency and fallback modes. You will take the technical details from the official Ministry of Finance documentation — but the architecture and the hard risk points are worth designing up front, before the penalty-free period ends.

At Mobilesoft we build backends and ERP integrations, including adapters to state systems such as KSeF. If you want to move from "we still have time" to a working, tested integration before the sanctions kick in — let's talk. We will help design the integration layer so that KSeF becomes invisible plumbing inside your system rather than a permanent fire in the accounting department.