Skip to content

For developers

KSeF 2.0 API developer guide: auth, sessions, FA(3), UPO, offline

Last reviewed NOT YET READY

KSeF 2.0 is the Polish Ministry of Finance's REST API for the National e-Invoice System. An integration authenticates with a challenge signed by a qualified certificate or encrypted with a KSeF token, exchanges the result for a short-lived JWT, opens a session with an AES key it generated, submits FA(3) XML invoices encrypted under that key, polls for their status, and downloads the UPO — the official receipt that gives an invoice its KSeF number and legal existence. This guide follows that sequence, then covers batch submission, the offline modes, limits and how KRONENWERK's KSeF module maps onto it.

Environments

Three public environments exist, and they are not interchangeable. Everything below applies to all three; the base URL selects which.

EnvironmentBase URLPurpose
TEST (TE)https://api-test.ksef.mf.gov.plIntegration testing against release-candidate versions. Self-signed certificates are accepted for authentication; data is shared between integrators and not isolated, so use random NIP numbers, never real ones.
DEMOhttps://api-demo.ksef.mf.gov.plPre-production validation mirroring the live configuration; real certificates required.
PRODUCTION (PRD)https://api.ksef.mf.gov.plInvoices with full legal effect.

The API documentation is served at /docs/v2 under each base URL, and the same OpenAPI description, guides and official client libraries (C# and Java) are published by the Ministry's CIRFMF organisation on GitHub. Since 1 October 2025 the test environments have scheduled maintenance windows (16:00–18:00), during which calls may fail. Never submit production invoices or real entity data to TEST or DEMO.

Authentication

Every protected call carries a JWT access token. Obtaining one is a five-step flow whose first and last steps are the same regardless of credential.

  1. Challenge. POST /auth/challenge returns a challenge value and timestamp. It is valid for 10 minutes.
  2. Prove identity, in one of two ways:
    • XAdES signature. Build an AuthTokenRequest XML containing the challenge, the context identifier (NIP, internal identifier or EU VAT identifier of the entity you act for) and the subject identifier type, sign it XAdES with a qualified certificate (personal or organisational qualified certificate, Trusted Profile, a KSeF certificate, or a Peppol provider certificate), and send it to POST /auth/xades-signature.
    • KSeF token. Concatenate {ksefToken}|{timestampMs}, encrypt with RSA-OAEP (SHA-256, MGF1) using the Ministry's published public key, Base64 it, and send it with the challenge and context to POST /auth/ksef-token. KSeF tokens are issued inside KSeF by someone who already holds authorisation for the entity; they suit unattended integrations.
    Either call returns a temporary authentication token and a reference number.
  3. Poll. GET /auth/{referenceNumber} with the temporary token until the status is final. Verification is asynchronous — the system checks the signature and the certificate against OCSP/CRL.
  4. Redeem. POST /auth/token/redeem exchanges the temporary token, once, for an accessToken (JWT, about 15 minutes, the exact lifetime is in its exp claim) and a refreshToken (about 7 days).
  5. Refresh. POST /auth/token/refresh with the refresh token returns a new access token carrying the entity's current permissions.

Permissions are granted in KSeF per entity and per role (issue, read, manage credentials, and so on); an access token reflects the permissions at issuance and is invalidated when they are withdrawn. An authorisation policy can restrict a token to IP addresses or ranges. Store both tokens as secrets.

Interactive session: submit, status, UPO

An interactive session submits invoices one at a time, synchronously on the wire and asynchronously in processing. It is the mode most invoicing software uses.

  1. Prepare a key. Generate a 256-bit AES key and a 128-bit IV. Encrypt the key with the Ministry's RSA public key (RSAES-OAEP, MGF1 with SHA-256). The Ministry's client libraries include a CryptographyService that does this.
  2. Open. POST /sessions/online with the schema version (FA(3) — the current invoice schema; FA(2) is still named in the documentation) and the encrypted key. The response carries a session referenceNumber and validUntil. A session lives for 12 hours, and several may be open in parallel under one access token.
  3. Send. POST /sessions/online/{referenceNumber}/invoices with the invoice encrypted AES-256-CBC with PKCS#7 padding and Base64-encoded, plus the SHA-256 hash and size of both the plain and the encrypted file. The response acknowledges receipt; validation against the schema and business rules starts immediately and asynchronously.
  4. Poll. GET /sessions/{referenceNumber}/invoices lists each invoice's status: accepted with a KSeF number, or rejected with a reason. Poll with back-off, not in a tight loop.
  5. Close. POST /sessions/online/{referenceNumber}/close ends the session and triggers generation of the collective UPO.
  6. Fetch the UPO. The UPO (Urzędowe Poświadczenie Odbioru) is a signed XML document listing the accepted invoices with their KSeF numbers and acceptance timestamps. Store it with the invoices: it is the proof that the invoice was issued in the legal sense.

The KSeF number, not your internal number, is what the buyer sees in their own KSeF inbox and what a payment reference may need to quote. The date of issue for VAT purposes is the date the invoice was accepted by KSeF, which can differ from the date in the FA(3) — a point that requires professional confirmation for any specific case.

Batch session

A batch session submits many invoices as one encrypted ZIP. It suits month-end runs and migrations.

  1. Put the FA(3) XML files into a ZIP.
  2. Split the ZIP binary into parts of at most 100 MB, numbered in order.
  3. Encrypt each part AES-256-CBC with the same key scheme as above; compute the SHA-256 and size of each encrypted part.
  4. POST /sessions/batch with the encrypted key, the ZIP metadata, the schema version and the part list. The response returns a referenceNumber and, per part, an upload URL, method and headers.
  5. Upload each part as raw binary to its URL. The upload window is 20 minutes per declared part, pooled.
  6. POST /sessions/batch/{referenceNumber}/close, then poll the session status and download the collective UPO as for an interactive session.

Both session types accept up to 10,000 invoices. An invoice may be at most 1 MB, or 3 MB with an attachment.

Reading invoices

The receiving side is symmetrical. POST /invoices/query/metadata returns invoice metadata for a subject type (issuer, recipient, and so on) and a date range, paged with pageOffset and pageSize. GET /invoices/ksef/{ksefNumber} downloads one invoice by KSeF number. For bulk retrieval, POST /invoices/exports starts an asynchronous export under an encryption key you supply, and GET /invoices/exports/{referenceNumber} reports progress and yields the encrypted package. An integration that must see every purchase invoice polls the metadata query incrementally rather than exporting repeatedly.

Offline modes

Three modes let a taxpayer issue outside KSeF and submit afterwards. Each has its own trigger and deadline, and each is legally distinct.

ModeTriggerSubmit byLegal basis (as cited by the Ministry)
offline24Taxpayer's choice, any timeNext working day after issueArt. 106nda VAT Act
offline (announced unavailability)Ministry announces KSeF unavailabilityNext working day after service is restoredArt. 106nh VAT Act, from 1 February 2026
awaryjny (failure)Ministry declares a KSeF failure7 working days after the failure endsArt. 106nf VAT Act, from 1 February 2026

An offline invoice is a normal FA(3) with two QR codes printed or embedded: KOD I, which lets the buyer verify the invoice in KSeF, and KOD II, which confirms the issuer's identity from their KSeF certificate. When submitting it later, set offlineMode: true on the send request in either session type. If KSeF becomes unavailable during the submission window, the deadline restarts and can run to 7 working days from the end of the outage.

Limits and errors

The Ministry documents limits per context (the entity you act for) and per credential rather than per API key: 10,000 invoices per session, 1 MB or 3 MB per invoice, 100 MB per batch part, and caps on certificate requests and active certificates per identifier (for a NIP, 300 requests and 100 active certificates at the time of reading). Request-rate limits exist — the documentation says the system restricts the number of requests to protect stability — and are described in a separate rate-limit document; design for HTTP 429 with retry and back-off rather than for a fixed figure.

Errors come back as an HTTP status with a JSON body describing the problem: 400 for malformed requests, 401 for a missing or expired token, 403 for a permission the token does not carry, and per-invoice validation errors reported in the session status rather than on the send call. Schema failures (the XML does not match FA(3)) and semantic failures (a NIP that does not exist, a date outside the allowed window, a duplicate) surface at different stages; read the status entry for each invoice rather than trusting a 2xx on the upload.

How KRONENWERK handles this

NOT YET READY KRONENWERK's KSeF 2.0 module implements the flow described above: token authentication (challenge, encrypted KSeF token, redeem, refresh), an interactive session with an AES key generated per session, FA(3) generation and submission, status polling, UPO retrieval and reading of received invoices. It is environment-dependent by configuration — the same code targets TEST, DEMO or production according to settings — and it has not been used against production KSeF. For that reason KRONENWERK does not currently sell subscriptions to Polish companies, and nothing on this page should be read as production acceptance. FA(3) generation itself is SUPPORTED WITH LIMITATIONS: the XML is produced and schema-checked at issuance, but transmission and the resulting KSeF number and UPO depend on the module being proven in production. The public API does not expose KSeF operations: POST /invoices/drafts creates a draft, issuing happens in the product, and no endpoint submits FA(3), returns a KSeF number or fetches a UPO. See KSeF integration for what the API offers, KSeF explained and FA(3) for the format, and the Poland hub and country page for the current status.

Frequently asked questions

Which credential should an integration use: certificate or KSeF token?

A KSeF token suits unattended server-to-server integrations; it is generated inside KSeF by a person who already holds authorisation for the entity and is used encrypted under the Ministry's public key. A qualified certificate with XAdES is the route for people and for obtaining a KSeF certificate in the first place. Which the entity may use is a permissions question for that entity.

When is an invoice "issued" in KSeF?

When KSeF accepts it and assigns a KSeF number, recorded in the UPO. Until then a submitted invoice is pending, and a rejected one was never issued. The consequences for the VAT date require professional confirmation.

Can I test with real company data?

No. The Ministry states that TEST data is shared between integrators and not isolated, and that production invoices and real entity data must never be sent to TEST or DEMO. Use random NIP numbers on TEST.

Does KRONENWERK submit invoices to production KSeF?

Not at the time of writing. The module is built and environment-dependent; it has not been used against production KSeF, and KRONENWERK does not sell subscriptions to Polish companies until that is proven.

What is the difference between FA(2) and FA(3)?

They are successive versions of the Ministry's logical structure for the structured invoice. FA(3) is the current schema for KSeF 2.0; the documentation still names FA(2) as a selectable schema version. Check the changelog for the acceptance dates of each in production.

Sources

  1. Ministry of Finance (CIRFMF) — KSeF 2.0 API documentation, repository overview read on
  2. Ministry of Finance (CIRFMF) — KSeF API 2.0 environments read on
  3. Ministry of Finance (CIRFMF) — Authentication read on
  4. Ministry of Finance (CIRFMF) — Interactive session read on
  5. Ministry of Finance (CIRFMF) — Batch session read on
  6. Ministry of Finance (CIRFMF) — Offline modes read on
  7. Ministry of Finance (CIRFMF) — Retrieving invoices read on
  8. Ministry of Finance (CIRFMF) — Limits read on
  9. Ministry of Finance — Scope of mandatory KSeF (ksef.podatki.gov.pl) read on
  10. KRONENWERK developer documentation read on

Start integrating

Read the quickstart Reference

Read next