Skip to content

Kody weryfikujące QR ​

21.08.2025

Kod QR (Quick Response) to graficzna reprezentacja tekstu, najczęściej adresu URL. W kontekście KSeF jest to zakodowany link zawierający dane identyfikujące fakturę — taki format pozwala na szybkie odczytanie informacji przy pomocy urządzeń końcowych (smartfonów lub skanerów optycznych). Dzięki temu link może być zeskanowany i przekierowany bezpośrednio do odpowiedniego zasobu systemu KSeF odpowiedzialnego za wizualizację i weryfikację faktury lub certyfikatu KSeF wystawcy.

Kody QR wprowadzono z myślą o sytuacjach, gdy faktura trafia do odbiorcy innym kanałem niż bezpośrednie pobranie z API KSeF (np. jako PDF, wydruk czy załącznik e-mail). W takich przypadkach każdy może:

  • sprawdzić, czy dana faktura rzeczywiście znajduje się w systemie KSeF i czy nie została zmodyfikowana,
  • pobrać jej wersję ustrukturyzowaną (plik XML) bez potrzeby kontaktu z wystawcą,
  • potwierdzić autentyczność wystawcy (w przypadku faktur offline).

Generowanie kodów (zarówno dla faktur online, jak i offline) odbywa się lokalnie w aplikacji klienta na podstawie danych zawartych w wystawionej fakturze. Kod QR musi być zgodny z normą ISO/IEC 18004:2024. Jeśli nie ma możliwości umieszczenia kodu bezpośrednio na fakturze (np. format danych tego nie pozwala), należy dostarczyć go odbiorcy jako oddzielny plik graficzny lub link.

Środowiska ​

Poniżej zestawiono adresy URL dla poszczególnych środowisk KSeF używanych do generowania kodów QR:

SkrótŚrodowiskoAdres (QR)
TETestowe
(Release Candidate)
https://qr-test.ksef.mf.gov.pl
DEMOPrzedprodukcyjne (Demo/Preprod)https://qr-demo.ksef.mf.gov.pl
PRDProdukcyjnehttps://qr.ksef.mf.gov.pl

Uwaga: Poniższe przykłady są przygotowane dla środowiska testowego (TE). Dla pozostałych środowisk należy wykonać analogicznie, używając odpowiedniego adresu URL z powyższej tabeli.

W zależności od trybu wystawienia (online czy offline) na wizualizacji faktury umieszczany jest:

  • w trybie online — jeden kod QR (KOD I), umożliwiający weryfikację i pobranie faktury z KSeF,
  • w trybie offline — dwa kody QR:
    • KOD I do weryfikacji faktury po jej przesłaniu do KSeF,
    • KOD II do potwierdzenia autentyczności wystawcy na podstawie certyfikatu KSeF.

1. KOD I – Weryfikacja i pobieranie faktury ​

KOD I zawiera link umożliwiający odczyt i weryfikację faktury w systemie KSeF. Po zeskanowaniu kodu QR lub kliknięciu w link użytkownik otrzyma uproszczoną prezentację podstawowych danych faktury oraz informację o jej obecności w systemie KSeF. Pełny dostęp do treści (np. pobranie pliku XML) wymaga wprowadzenie dodatkowych danych.

Generowanie linku ​

Link składa się z:

  • adresu URL: https://qr-test.ksef.mf.gov.pl/invoice,
  • daty wystawienia faktury (pole P_1) w formacie DD-MM-RRRR,
  • NIP-u sprzedawcy,
  • skrótu pliku faktury obliczonego algorytmem SHA-256 (wyróżnik pliku faktury) w formacie Base64URL.

Przykładowo dla faktury:

  • data wystawienia: "01-02-2026",
  • NIP sprzedawcy: "1111111111",
  • skrót SHA-256 w formacie Base64URL: "UtQp9Gpc51y-u3xApZjIjgkpZ01js-J8KflSPW8WzIE"

Wygenerowany link wygląda następująco:

https://qr-test.ksef.mf.gov.pl/invoice/1111111111/01-02-2026/UtQp9Gpc51y-u3xApZjIjgkpZ01js-J8KflSPW8WzIE

Przykład w języku C#: KSeF.Client.Tests.Core\E2E\QrCode\QrCodeOnlineE2ETests.cs

csharp
string url = linkSvc.BuildInvoiceVerificationUrl(nip, issueDate, invoiceHash);

Przykład w języku Java:

java
String url = linkSvc.buildInvoiceVerificationUrl(nip, issueDate, xml);

Generowanie kodu QR ​

Przykład w języku C#: KSeF.Client.Tests.Core\E2E\QrCode\QrCodeE2ETests.cs

csharp
private const int PixelsPerModule = 5;
byte[] qrBytes = qrCodeService.GenerateQrCode(url, PixelsPerModule);

Przykład w języku Java: QrCodeOnlineIntegrationTest.java

java
byte[] qrOnline = qrCodeService.generateQrCode(invoiceForOnlineUrl);

Oznaczenie pod kodem QR ​

Proces przyjęcia faktury przez KSeF zazwyczaj przebiega natychmiastowo — numer KSeF generowany jest niezwłocznie po przesłaniu dokumentu. W wyjątkowych przypadkach (np. wysokie obciążenie systemu) numer może być nadany z niewielkim opóźnieniem.

  • Jeżeli numer KSeF jest znany: pod kodem QR umieszczany jest numer KSeF faktury (dotyczy faktur online oraz faktur offline już przesłanych do systemu).

QR KSeF

  • Jeżeli numer KSeF nie jest jeszcze nadany: pod kodem QR umieszczany jest napis OFFLINE (dotyczy faktur offline przed przesłaniem lub online oczekujących na numer).

QR Offline

Przykład w języku C#: KSeF.Client.Tests.Core\E2E\QrCode\QrCodeE2ETests.cs

csharp
byte[] labeled = qrCodeService.AddLabelToQrCode(qrBytes, GeneratedQrCodeLabel);

Przykład w języku Java: QrCodeOnlineIntegrationTest.java

java
byte[] qrOnline = qrCodeService.addLabelToQrCode(qrOnline, invoiceKsefNumber);

2. KOD II - Weryfikacja certyfikatu ​

KOD II jest generowany wyłącznie dla faktur wystawianych w trybie offline (offline24, offline-niedostępność systemu, tryb awaryjny) i pełni funkcję potwierdzenia autentyczności wystawcy oraz jego uprawnień do wystawienia faktury w imieniu sprzedawcy. Generowanie wymaga posiadania aktywnego certyfikatu KSeF typu Offline – link zawiera kryptograficzny podpis URL przy użyciu klucza prywatnego certyfikatu KSeF typu Offline, co zapobiega sfałszowaniu linku przez podmioty nieposiadające dostępu do certyfikatu.

Uwaga: Certyfikat typu Authentication nie może być używany do generowania KODU II. Jego przeznaczeniem jest wyłącznie uwierzytelnienie w API.

Certyfikat KSeF typu Offline można pozyskać za pomocą endpointu /certificates.

Weryfikacja po zeskanowaniu kodu QR II ​

Po przejściu do linku z kodu QR system KSeF dokonuje automatycznej weryfikacji certyfikatu wystawcy. Proces ten obejmuje następujące etapy:

  1. Certyfikat KSeF wystawcy

    • Certyfikat istnieje w rejestrze certyfikatów KSeF i jest ważny.
    • Certyfikat nie został odwołany, zablokowany ani nie utracił ważności (validTo).
  2. Podpis wystawcy

    • System weryfikuje poprawność podpisu dołączonego w URL.
  3. Uprawnienia wystawcy

    • Podmiot identyfikowany przez certyfikat wystawcy posiada aktywne uprawnienia do wystawienia faktury w kontekście (ContextIdentifier),
    • Weryfikacja odbywa się zgodnie z zasadami opisanymi w dokumencie uwierzytelnianie.md,
    • Przykładowo: księgowa podpisująca fakturę w imieniu firmy A musi mieć nadane prawo InvoiceWrite w kontekście tej firmy.
  4. Zgodność kontekstu i NIP sprzedawcy

    • System sprawdza, czy kontekst (ContextIdentifier) ma prawo do wystawiania faktury dla danego NIP-u sprzedawcy (Podmiot1 faktury). Dotyczy to m.in. przypadków:
      • samofakturowania (SelfInvoicing),
      • przedstawiciel podatkowy (TaxRepresentative),
      • grup VAT,
      • jednostek JST,
      • jednostek podrzędnych identyfikowanych identyfikatorem wewnętrzym,
      • komornik,
      • organ egzekucyjny,
      • faktur PEF wystawianych w imieniu innego podmiotu przez dostawcę usług Peppol,
      • faktur wystawionych przez podmiot europejski.

    Przykład 1. Wystawienie faktury przez podmiot we własnym kontekście

    Podmiot wystawia fakturę, używając certyfikatu zawierającego jego własny numer NIP. Faktura jest wystawiana w kontekście tego samego podmiotu, a w polu NIP sprzedawcy wskazany jest jego własny numer NIP.

    Identyfikator wystawcy (certyfikat)KontekstNIP sprzedawcy
    111111111111111111111111111111

    Przykład 2. Wystawienie faktury przez osobę uprawnioną w imieniu podmiotu

    Osoba fizyczna (np. księgowa) posługująca się certyfikatem KSeF zawierającym numer PESEL wystawia fakturę w kontekście podmiotu, w imieniu którego posiada odpowiednie uprawnienia. W polu NIP sprzedawcy wskazany jest numer NIP tego podmiotu.

    Identyfikator wystawcy (certyfikat)KontekstNIP sprzedawcy
    2222222222211111111111111111111

    Przykład 3. Wystawienie faktury w imieniu innego podmiotu

    Osoba fizyczna wystawia fakturę w kontekście podmiotu A, jednak na fakturze w polu NIP sprzedawcy wskazany jest numer NIP innego podmiotu B. Sytuacja ta jest możliwa, gdy podmiot A posiada nadane uprawnienia wystawiania faktur w imieniu podmiotu B np. przedstawiciel podatkowy, samofakturowanie.

    Identyfikator wystawcy (certyfikat)KontekstNIP sprzedawcy
    2222222222211111111113333333333

Generowanie linku ​

Link weryfikacyjny składa się z:

  • adresu URL: https://qr-test.ksef.mf.gov.pl/certificate,
  • typu identyfikatora kontekstu logowania (ContextIdentifier): "Nip", "InternalId", "NipVatUe", "PeppolId"
  • wartości identyfikatora kontekstu logowania,
  • NIP-u sprzedawcy,
  • numeru seryjnego certyfikatu KSeF wystawcy,
  • skrótu pliku faktury SHA-256 w formacie Base64URL,
  • podpisu linku przy użyciu klucza prywatnego certyfikatu KSeF wystawcy (zakodowany w formacie Base64URL).

Format podpisu
Do podpisu używany jest fragment ścieżki URL bez prefiksu protokołu (https://) i bez końcowego znaku /, np.:

qr-test.ksef.mf.gov.pl/certificate/Nip/1111111111/1111111111/01F20A5D352AE590/UtQp9Gpc51y-u3xApZjIjgkpZ01js-J8KflSPW8WzIE

Algorytmy podpisu:

  • RSA (RSASSA-PSS)

    • Funkcja skrótu: SHA-256
    • MGF: MGF1 z SHA-256
    • Długość losowej domieszki (soli): 32 bajty
    • Wymagana długość klucza: Minimum 2048 bity.

    Ciąg do podpisu jest najpierw haszowany algorytmem SHA-256, a następnie generowany jest podpis zgodnie ze schematem RSASSA-PSS.

  • ECDSA (P-256/SHA-256)
    Ciąg do podpisu jest haszowany algorytmem SHA-256, a następnie generowany jest podpis z użyciem klucza prywatnego ECDSA opartego na krzywej NIST P-256 (secp256r1), której wybór należy wskazać podczas generowania CSR.

    Wartość podpisu to para liczb całkowitych (r, s). Może być zakodowana w jednym z dwóch formatów:

    • IEEE P1363 Fixed Field Concatenation – rekomendowany sposób z uwagi na krótszy ciąg wynikowy i stałą długość. Format prostszy i krótszy niż DER. Podpis to konkatenacja R || S (po 32 bajty big-endian).
    • ASN.1 DER SEQUENCE (RFC 3279) – podpis jest kodowany jako ASN.1 DER. Rozmiar podpisu jest zmienny. Proponujemy użycie tego rodzaju podpisu tylko, gdy IEEE P1363 nie jest możliwy z powodu ograniczeń technologicznych.

W obu przypadkach (niezależnie od wyboru RSA czy ESDSA) otrzymaną wartość podpisu należy zakodować w formacie Base64URL.

Przykładowo dla faktury:

  • typ identyfikatora kontekstu logowania: "Nip",
  • wartość identyfikatora kontekstu: "1111111111",
  • NIP sprzedawcy: "1111111111",
  • numer seryjny certyfikatu KSeF wystawcy: "01F20A5D352AE590",
  • skrót SHA-256 w formacie Base64URL: "UtQp9Gpc51y-u3xApZjIjgkpZ01js-J8KflSPW8WzIE",
  • podpisu linku przy użyciu klucza prywatnego certyfikatu KSeF wystawcy: "mSkm_XmM9fq7PgAJwiL32L9ujhyguOEV48cDB0ncemD2r9TMGa3lr0iRoFk588agCi8QPsOuscUY1rZ7ff76STbGquO-gZtQys5_fHdf2HUfDqPqVTnUS6HknBu0zLkyf9ygoW7WbH06Ty_8BgQTlOmJFzNWSt9WZa7tAGuAE9JOooNps-KG2PYkkIP4q4jPMp3FKypAygHVnXtS0RDGgOxhhM7LWtFP7D-dWINbh5yXD8Lr-JVbeOpyQjHa6WmMYavCDQJ3X_Z-iS01LZu2s1B3xuOykl1h0sLObCdADrbxOONsXrvQa61Xt_rxyprVraj2Uf9pANQgR4-12HEcMw"

Wygenerowany link wygląda następująco:

https://qr-test.ksef.mf.gov.pl/certificate/Nip/1111111111/1111111111/01F20A5D352AE590/UtQp9Gpc51y-u3xApZjIjgkpZ01js-J8KflSPW8WzIE/mSkm_XmM9fq7PgAJwiL32L9ujhyguOEV48cDB0ncemD2r9TMGa3lr0iRoFk588agCi8QPsOuscUY1rZ7ff76STbGquO-gZtQys5_fHdf2HUfDqPqVTnUS6HknBu0zLkyf9ygoW7WbH06Ty_8BgQTlOmJFzNWSt9WZa7tAGuAE9JOooNps-KG2PYkkIP4q4jPMp3FKypAygHVnXtS0RDGgOxhhM7LWtFP7D-dWINbh5yXD8Lr-JVbeOpyQjHa6WmMYavCDQJ3X_Z-iS01LZu2s1B3xuOykl1h0sLObCdADrbxOONsXrvQa61Xt_rxyprVraj2Uf9pANQgR4-12HEcMw

Przykład w języku C#: KSeF.Client.Tests.Core\E2E\QrCode\QrCodeOfflineE2ETests.cs

csharp
 var certificate = new X509Certificate2(Convert.FromBase64String(certbase64));

 byte[] qrOfflineCode = QrCodeService.GenerateQrCode(
    linkService.BuildCertificateVerificationUrl(
        nip,
        nip,
        certificate.CertificateSerialNumber,
        invoiceHash,
        certificate));

Przykład w języku Java: QrCodeOfflineIntegrationTest.java

java
String pem = privateKeyPemBase64.replaceAll("\\s+", "");
byte[] keyBytes = java.util.Base64.getDecoder().decode(pem);

String url = verificationLinkService.buildCertificateVerificationUrl(
    contextNip,
    ContextIdentifierType.NIP,
    contextNip,
    certificate.getCertificateSerialNumber(),
    invoiceHash,
    cryptographyService.parsePrivateKeyFromPem(keyBytes));

Generowanie QR kodu ​

Przykład w języku C#: KSeF.Client.Tests.Core\E2E\QrCode\QrCodeE2ETests.cs

csharp
byte[] qrBytes = qrCodeService.GenerateQrCode(url, PixelsPerModule);

Przykład w języku Java: QrCodeOnlineIntegrationTest.java

java
byte[] qrOnline = qrCodeService.generateQrCode(invoiceForOnlineUrl);

Oznaczenie pod kodem QR ​

Pod kodem QR powinien znaleźć się podpis CERTYFIKAT, wskazujący na funkcję weryfikacji certyfikatu KSeF.

Przykład w języku C#: KSeF.Client.Tests.Core\E2E\QrCode\QrCodeE2ETests.cs

csharp
private const string GeneratedQrCodeLabel = "CERTYFIKAT";
byte[] labeled = qrCodeService.AddLabelToQrCode(qrBytes, GeneratedQrCodeLabel);

Przykład w języku Java: QrCodeOnlineIntegrationTest.java

java
byte[] qrOnline = qrCodeService.addLabelToQrCode(qrOnline, invoiceKsefNumber);

QR  Certyfikat