implementation7 min read

KSeF API Developer Guide 2026: How to Integrate with Poland's E-Invoicing System

Complete developer guide to the KSeF API in Poland. Authentication, FA_VAT XML generation, invoice submission, status polling, offline mode handling, and testing environment setup.

By EU E-Invoicing HubPublished: 5 May 2026Updated: 8 May 2026

KSeF API Developer Guide 2026: Integrating with Poland's National E-Invoicing System

This guide is for developers integrating their applications โ€” ERP systems, accounting software, e-commerce platforms, or custom business applications โ€” with the Polish KSeF (Krajowy System e-Faktur) API.

What Is KSeF?

KSeF is Poland's centralised government e-invoicing platform. Every domestic Polish B2B invoice must be submitted to KSeF, which:

  1. Validates the FA_VAT XML against the Ministry of Finance schema
  2. Assigns a unique KSeF reference number (numer referencyjny KSeF)
  3. Makes the invoice available to the buyer via KSeF
  4. Stores the invoice for the statutory retention period

Unlike Italy's SDI (which routes invoices between businesses), KSeF is a clearing house โ€” both the seller and buyer access the invoice via the KSeF platform using the KSeF reference number.

KSeF API Overview

The KSeF API is a REST API operated by the Polish Ministry of Finance (Ministerstwo Finansรณw).

Environment Base URL
Production https://ksef.mf.gov.pl/api
Test/staging https://ksef-test.mf.gov.pl/api
Demo https://ksef-demo.mf.gov.pl/api

Always develop and test against the test environment (ksef-test.mf.gov.pl).

Authentication

KSeF uses a session token model with cryptographic challenge-response authentication. The process:

Step 1: Generate an Authentication Token

Authentication tokens are generated in the KSeF portal (or via the API) and tied to your company's NIP (Polish tax ID). Tokens are valid for up to 30 days.

Store your token securely โ€” treat it like an API key.

Step 2: Initialize a Session

POST https://ksef-test.mf.gov.pl/api/online/Session/AuthorisationChallenge
Content-Type: application/json

{
  "contextIdentifier": {
    "type": "onip",
    "identifier": "1234567890"  // Your NIP (10 digits)
  }
}

Response includes a challenge string that you must encrypt with your KSeF token.

Step 3: Authorise the Session

POST https://ksef-test.mf.gov.pl/api/online/Session/Authorise
Content-Type: application/json

{
  "contextIdentifier": {
    "type": "onip",
    "identifier": "1234567890"
  },
  "authorisationCode": "BASE64_ENCODED_ENCRYPTED_CHALLENGE"
}

Response returns a sessionToken that you use for subsequent requests.

Generating FA_VAT XML

FA_VAT (Faktura VAT) is the XML schema mandated by the Ministry of Finance. The current version is FA(2) (schema version 2.0).

Minimal FA_VAT Invoice Example

<?xml version="1.0" encoding="UTF-8"?>
<Faktura xmlns="http://crd.gov.pl/wzor/2023/06/29/12648/"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  
  <Naglowek>
    <KodFormularza kodSystemowy="FA (2)" wersjaSchemy="1-0E">FA</KodFormularza>
    <WariantFormularza>2</WariantFormularza>
    <DataWytworzeniaFa>2026-05-01T10:00:00</DataWytworzeniaFa>
    <!-- Your invoice identifier -->
    <NazwaSystemu>YOUR_SYSTEM_NAME</NazwaSystemu>
  </Naglowek>
  
  <Podmiot1>
    <!-- Seller -->
    <PrefiksMiejscaDostawy>PL</PrefiksMiejscaDostawy>
    <DaneIdentyfikacyjne>
      <NIP>1234567890</NIP>  <!-- Seller NIP -->
      <PelnaNazwa>Seller Company Sp. z o.o.</PelnaNazwa>
    </DaneIdentyfikacyjne>
    <Adres>
      <KodKraju>PL</KodKraju>
      <AdresL1>ul. Przykล‚adowa 1, 00-000 Warszawa</AdresL1>
    </Adres>
  </Podmiot1>
  
  <Podmiot2>
    <!-- Buyer -->
    <DaneIdentyfikacyjne>
      <NIP>0987654321</NIP>  <!-- Buyer NIP -->
      <PelnaNazwa>Buyer Company Sp. z o.o.</PelnaNazwa>
    </DaneIdentyfikacyjne>
    <Adres>
      <KodKraju>PL</KodKraju>
      <AdresL1>ul. Testowa 5, 00-001 Krakรณw</AdresL1>
    </Adres>
  </Podmiot2>
  
  <Fa>
    <KodWaluty>PLN</KodWaluty>
    <P_1>2026-05-01</P_1>   <!-- Invoice date -->
    <P_2>FV/2026/05/001</P_2> <!-- Invoice number -->
    <P_6>2026-05-31</P_6>   <!-- Sale date -->
    
    <!-- Line items -->
    <FaWiersz>
      <NrWierszaFa>1</NrWierszaFa>
      <P_7>Software development services</P_7> <!-- Description -->
      <P_8A>szt.</P_8A>  <!-- Unit -->
      <P_8B>10</P_8B>    <!-- Quantity -->
      <P_9A>1500.00</P_9A>  <!-- Net unit price -->
      <P_11>15000.00</P_11> <!-- Net total -->
      <P_12>23</P_12>  <!-- VAT rate % -->
    </FaWiersz>
    
    <!-- VAT totals -->
    <RodzajFaktury>VAT</RodzajFaktury>
    <P_13_1>15000.00</P_13_1>  <!-- Net (23% rate) -->
    <P_14_1>3450.00</P_14_1>   <!-- VAT amount (23%) -->
    <P_15>18450.00</P_15>     <!-- Gross total -->
    
    <!-- Payment -->
    <Platnosc>
      <TerminPlatnosci>
        <Termin>2026-05-31</Termin>
      </TerminPlatnosci>
      <FormaPlatnosci>6</FormaPlatnosci>  <!-- Bank transfer -->
      <RachunekBankowy>
        <NrRB>PL61109010140000071219812874</NrRB>
      </RachunekBankowy>
    </Platnosc>
  </Fa>
  
</Faktura>

Key Field References

Field Description Notes
P_1 Invoice date YYYY-MM-DD
P_2 Invoice number Sequential, per your numbering system
P_6 Sale date Date of service delivery
P_7 Line item description
P_12 VAT rate 23, 8, 5, 0, or ZW (exempt)
P_13_x Net amount by VAT rate Separate field per rate group
P_14_x VAT amount by VAT rate
P_15 Gross total Must equal sum of all P_13 + P_14

Submitting an Invoice to KSeF

POST https://ksef-test.mf.gov.pl/api/online/Invoice/Send
SessionToken: YOUR_SESSION_TOKEN
Content-Type: application/json

{
  "invoiceHash": {
    "hashSHA": {
      "algorithm": "SHA-256",
      "encoding": "Base64",
      "value": "SHA256_HASH_OF_YOUR_FA_VAT_XML"
    },
    "fileSize": 4096
  },
  "invoicePayload": {
    "type": "plain",
    "invoiceBody": "BASE64_ENCODED_FA_VAT_XML"
  }
}

Success Response

{
  "timestamp": "2026-05-01T10:15:30Z",
  "referenceNumber": "1234567890-20260501-ABCDE-12345"
}

The referenceNumber is your KSeF numer referencyjny โ€” store this against the invoice in your system. The buyer uses this to access the invoice from KSeF.

Polling for Invoice Status

After submission, poll for the processing result:

GET https://ksef-test.mf.gov.pl/api/online/Invoice/Status/{referenceNumber}
SessionToken: YOUR_SESSION_TOKEN

Response statuses:

  • RECEIVED โ€” KSeF received the invoice but hasn't processed it yet
  • VERIFIED โ€” Processing successful, invoice is valid
  • ERROR โ€” Validation failed โ€” check processingCode for details

Handling KSeF Downtime: Offline Mode

KSeF is occasionally unavailable (maintenance windows, typically Sunday nights). During unavailability, you must implement offline mode:

  1. Detect unavailability โ€” KSeF API returns a 503 status or specific error code
  2. Generate offline invoice โ€” The FA_VAT XML is the same, but you store it locally without a KSeF reference number
  3. Issue to buyer โ€” You may issue the invoice to the buyer without the KSeF number (buyer knows to expect retroactive reference)
  4. Submit within 72 hours โ€” Once KSeF is restored, submit the offline invoice within 72 hours
  5. Store the KSeF reference retroactively โ€” Update your records with the KSeF number received after submission
import requests
from datetime import datetime

def submit_invoice(invoice_xml: str, session_token: str, offline_fallback: bool = True):
    try:
        response = requests.post(
            "https://ksef.mf.gov.pl/api/online/Invoice/Send",
            headers={"SessionToken": session_token},
            json={
                "invoicePayload": {
                    "type": "plain",
                    "invoiceBody": base64_encode(invoice_xml)
                }
            },
            timeout=30
        )
        response.raise_for_status()
        return response.json()["referenceNumber"]
    
    except (requests.Timeout, requests.ConnectionError, requests.HTTPError) as e:
        if offline_fallback:
            # Store in offline queue
            store_offline(invoice_xml, datetime.now())
            return None  # No KSeF ref yet โ€” will be assigned when submitted
        raise

Corrective Invoices (Faktura Korygujฤ…ca)

When correcting a previously issued KSeF invoice:

<Fa>
  <!-- Reference to original invoice -->
  <NrKSeFFaKorygowanej>1234567890-20260401-XXXXX-00001</NrKSeFFaKorygowanej>
  
  <!-- Type must indicate correction -->
  <RodzajFaktury>KOR</RodzajFaktury>
  
  <!-- ... rest of corrected invoice fields ... -->
</Fa>

Critical: Use the KSeF reference number of the original invoice โ€” not your internal invoice number.

Testing Your Integration

  1. Use the test environment (ksef-test.mf.gov.pl) โ€” it mirrors production behaviour
  2. Validate XML first โ€” use the Ministry of Finance XML validator before submitting to KSeF
  3. Test all invoice types: standard, corrective, advance payment, split payment (MPP)
  4. Simulate offline mode โ€” the test environment has a simulated downtime mode
  5. Test token expiry โ€” set a short expiry on your test token and verify your expiry handling

Online Validator

https://ksef.mf.gov.pl/ksef/web/#/ksef/walidacja-faktury

Upload your FA_VAT XML for instant validation.

Common Error Codes

Code Meaning Fix
02001 Invalid NIP format Verify seller/buyer NIP is exactly 10 digits
02002 NIP not active in VIES Buyer NIP not registered โ€” check with buyer
03001 XML schema validation failure Check your FA(2) XML against the MF schema
05001 Invoice number already submitted Duplicate invoice number โ€” use a unique one
09001 Session token expired Refresh your session token

Libraries and Tools

Tool Language Notes
ksef-python Python Community library for KSeF API
ksef-java-sdk Java Official MF reference implementation
KSeF Online Validator Browser Official validation tool
fa-vat-validator Python FA_VAT schema validation

Production Checklist

Before going live with your KSeF integration:

  • All invoice types validated against FA(2) schema
  • Session token rotation implemented (before 30-day expiry)
  • Offline mode implemented and tested
  • KSeF reference number stored in your database per invoice
  • Corrective invoice handling tested with KSeF reference
  • Error code handling for all documented error codes
  • Integration tested in the KSeF test environment with real NIP numbers

Resources

ksefapideveloperpolandfa-vatintegrationxmlrest-api