15.08.2026

Przykład integracji z API KSeF krok po kroku – od danych faktury do numeru KSeF i UPO

Przykład integracji z API KSeF krok po kroku – od danych faktury do numeru KSeF i UPO

W poprzednim artykule opisaliśmy, jak wygląda integracja z API KSeF od strony architektury — ten wpis jest jego praktycznym uzupełnieniem. Zamiast ogólnego omówienia procesu, przechodzimy przez konkretny, działający przykład: od pojedynczej transakcji sprzedaży, przez przygotowanie danych, po odebranie numeru KSeF i UPO. Całość na przykładzie API KSeFService — środowisko TEST, gotowy kod PHP, realistyczne dane wejściowe.

Scenariusz

Załóżmy prosty, ale realistyczny przypadek: firma sprzedała usługę konsultingową kontrahentowi firmowemu. Mamy dane transakcji w naszym systemie (np. w tabeli zamówień) i chcemy automatycznie wystawić z nich fakturę w KSeF. To dokładnie ten sam scenariusz, który powtarza się przy każdej integracji sklepu, ERP czy systemu fakturującego — zmieniają się tylko źródła danych.

Krok 1 — dane wejściowe

Zanim cokolwiek wyślemy, musimy mieć komplet danych po stronie naszego systemu:

$order = [
    'seller' => [
        'nip'  => '1234567890',
        'name' => 'Moja Firma Sp. z o.o.',
        'address' => 'ul. Testowa 1, 00-001 Warszawa',
    ],
    'buyer' => [
        'nip'  => '9876543210',
        'name' => 'Kontrahent Sp. z o.o.',
        'address' => 'ul. Przykładowa 5, 00-002 Warszawa',
    ],
    'items' => [
        [
            'name'      => 'Usługa konsultingowa',
            'quantity'  => 1,
            'net_price' => 2000.00,
            'vat_rate'  => 23,
        ],
    ],
    'payment_method' => 'przelew',
    'issue_date'     => date('Y-m-d'),
];

To dane, jakie realnie miałbyś np. w tabeli zamówień sklepu albo w rekordzie faktury z systemu księgowego — nic w tym momencie nie jest jeszcze związane z formatem KSeF.

Krok 2 — dane dostępowe do API

Do wysyłki potrzebujemy danych logowania do konta KSeFService oraz wskazania środowiska. Na etapie developmentu i testów zawsze używamy środowiska TEST — nigdy produkcyjnego:

$clientId = 'TWOJ_CLIENT_ID';
$login    = 'twoj_login';
$password = 'twoje_haslo';
$apiEnv   = 'TEST'; // TEST | DEMO | PROD

Krok 3 — przygotowanie faktury FA(3)

Zamiast ręcznie budować cały XML zgodny ze schematem FA(3) (co wymaga dokładnej znajomości struktury i kolejności elementów), korzystamy z endpointu, który przyjmuje dane w prostszym, ustrukturyzowanym formacie i sam generuje poprawny dokument:

$payload = [
    'clientId' => $clientId,
    'login'    => $login,
    'password' => $password,
    'api_env'  => $apiEnv,
    'seller'   => $order['seller'],
    'buyer'    => $order['buyer'],
    'items'    => $order['items'],
    'payment_method' => $order['payment_method'],
    'issue_date'      => $order['issue_date'],
];

$ch = curl_init('https://ksefservice.pl/api/v1/invoices/fa3');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($payload),
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_RETURNTRANSFER => true,
]);
$response = curl_exec($ch);
$ch = null;

$result = json_decode($response, true);
$xmlContent = $result['data']['xml'] ?? null;

Na tym etapie otrzymujemy gotowy dokument XML zgodny ze schematem FA(3) — możemy go zwalidować, zapisać do archiwum lub od razu przekazać do wysyłki.

Krok 4 — wysyłka do KSeF

Dokument trafia do endpointu odpowiedzialnego za komunikację z Krajowym Systemem e-Faktur:

$tmpFile = tempnam(sys_get_temp_dir(), 'fa3_') . '.xml';
file_put_contents($tmpFile, $xmlContent);

$file = new CURLFile($tmpFile, 'application/xml', 'invoice_FA3.xml');
$postFields = [
    'clientId' => $clientId,
    'login'    => $login,
    'password' => $password,
    'api_env'  => $apiEnv,
    'file'     => $file,
];

$ch = curl_init('https://ksefservice.pl/api/v1/invoices/send');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => $postFields,
    CURLOPT_RETURNTRANSFER => true,
]);
$sendResponse = curl_exec($ch);
$ch = null;
unlink($tmpFile);

Krok 5 — odczyt odpowiedzi

Odpowiedź zawiera informację o statusie przetworzenia oraz, przy powodzeniu, numer KSeF:

{
  "success": true,
  "stage": "ksef_ok",
  "data": {
    "ksefNumber": "5771876968-20251209-0100805B192F-B3",
    "sessionReference": "20251209-SO-178C9DF000-9498D48B5B-BB"
  }
}

W kodzie odczytujemy i zapisujemy te wartości w naszym systemie źródłowym — to one są dowodem, że faktura trafiła do KSeF, i to je trzeba przypisać do rekordu zamówienia czy faktury w bazie danych:

$sendResult = json_decode($sendResponse, true);

if ($sendResult['success'] ?? false) {
    $ksefNumber = $sendResult['data']['ksefNumber'];
    $sessionRef = $sendResult['data']['sessionReference'];
    // zapis $ksefNumber i $sessionRef w tabeli zamówień/faktur
} else {
    // obsługa błędu — zapisanie treści odpowiedzi do logu
}

Krok 6 — pobranie UPO

Numer KSeF potwierdza nadanie identyfikatora, ale to Urzędowe Poświadczenie Odbioru (UPO) jest formalnym dowodem doręczenia faktury do systemu. Pobieramy je osobnym żądaniem, na podstawie numeru referencyjnego sesji:

$upoPayload = [
    'clientId' => $clientId,
    'login'    => $login,
    'password' => $password,
    'api_env'  => $apiEnv,
    'sessionReference' => $sessionRef,
    'ksefNumber'       => $ksefNumber,
];

$ch = curl_init('https://ksefservice.pl/api/v1/invoices/upo');
curl_setopt_array($ch, [
    CURLOPT_POST => true,
    CURLOPT_POSTFIELDS => json_encode($upoPayload),
    CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
    CURLOPT_RETURNTRANSFER => true,
]);
$upoResponse = curl_exec($ch);
$ch = null;

// zapis UPO (XML) do archiwum, powiązany z numerem KSeF

Pobrane UPO warto zarchiwizować razem z oryginalnym dokumentem faktury — to ono, a nie sam fakt wysłania żądania, jest dowodem zgodności z obowiązkiem prawnym.

Cały proces w skrócie

  1. Zbierz dane transakcji w swoim systemie (zamówienie, faktura, dokument sprzedaży).
  2. Wygeneruj dokument FA(3) na podstawie tych danych.
  3. Wyślij dokument do KSeF.
  4. Odczytaj numer KSeF ze odpowiedzi i zapisz go w swoim systemie.
  5. Pobierz UPO i zarchiwizuj je razem z fakturą.

Każdy z tych kroków, mimo że tutaj pokazany osobno dla przejrzystości, w produkcyjnej integracji zwykle łączy się w jeden spójny proces uruchamiany automatycznie po zdarzeniu biznesowym (np. zmianie statusu zamówienia na „opłacone").

Co dalej po tym przykładzie

  • Dodaj obsługę błędów — sprawdzaj pole success i loguj pełną treść odpowiedzi przy niepowodzeniu.
  • Zaimplementuj retry dla błędów przejściowych (5xx), zanim uznasz wysyłkę za nieudaną.
  • Przetestuj cały proces na środowisku TEST, zanim przełączysz api_env na PROD.
  • Jeśli integrujesz się z konkretną platformą (sklep, ERP), sprawdź gotowe przykłady dla PHP, Node.js, .NET, Java, React i Angular.

Podsumowanie

Powyższy przykład pokazuje pełny cykl integracji z API KSeF na konkretnych, działających danych — od transakcji w Twoim systemie, przez wygenerowanie faktury FA(3), po numer KSeF i UPO. To ten sam schemat, który powtarza się w każdej integracji, niezależnie od tego, czy źródłem danych jest sklep internetowy, ERP czy własny system fakturujący.

Chcesz przetestować ten przykład na własnym koncie? Skontaktuj się z nami, żeby uzyskać dostęp do środowiska TEST, lub sprawdź pełną dokumentację API z przykładami.