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.
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:
- Validates the FA_VAT XML against the Ministry of Finance schema
- Assigns a unique KSeF reference number (numer referencyjny KSeF)
- Makes the invoice available to the buyer via KSeF
- 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 yetVERIFIEDโ Processing successful, invoice is validERRORโ Validation failed โ checkprocessingCodefor details
Handling KSeF Downtime: Offline Mode
KSeF is occasionally unavailable (maintenance windows, typically Sunday nights). During unavailability, you must implement offline mode:
- Detect unavailability โ KSeF API returns a 503 status or specific error code
- Generate offline invoice โ The FA_VAT XML is the same, but you store it locally without a KSeF reference number
- Issue to buyer โ You may issue the invoice to the buyer without the KSeF number (buyer knows to expect retroactive reference)
- Submit within 72 hours โ Once KSeF is restored, submit the offline invoice within 72 hours
- 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
- Use the test environment (
ksef-test.mf.gov.pl) โ it mirrors production behaviour - Validate XML first โ use the Ministry of Finance XML validator before submitting to KSeF
- Test all invoice types: standard, corrective, advance payment, split payment (MPP)
- Simulate offline mode โ the test environment has a simulated downtime mode
- 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