Dokumentacja

Przewodnik po aplikacji KSeFka

CLI — interfejs wiersza poleceń#

KSeFka dostarcza CLI (ksefka) do zarządzania fakturami, kontrahentami i danymi bezpośrednio z terminala lub skryptów. Większość komend wymaga licencji PRO (bez niej działają m.in. status, authorize i lista produktów). Każda instalacja ma 30 dni okresu próbnego, wspólnego z aplikacją i MCP; rusza przy pierwszym uruchomieniu aplikacji albo pierwszej komendzie CLI.

Instalacja#

CLI jest dołączone do instalatora KSeFka, ale nie włącza się samo. Otwórz Ustawienia → CLI i kliknij "Zainstaluj CLI" — dopiero wtedy polecenie ksefka pojawia się w terminalu. Na Windows instalator aplikacji dodaje katalog instalacji do zmiennej PATH, więc nic więcej nie trzeba ustawiać.

Kolejne wersje CLI aplikacja podmienia sama, o ile CLI jest już zainstalowane.

Weryfikacja instalacji:

ksefka --version

Opcje globalne#

OpcjaOpis
--env <środowisko>Środowisko KSeF: test, demo, production (domyślnie: środowisko wybrane ostatnio w aplikacji)
--company-id <ID>ID firmy, gdy masz w aplikacji kilka firm (domyślnie: firma aktywna w aplikacji)
--helpWyświetl pomoc dla komendy

Jak znaleźć pomoc#

Każda komenda ma wbudowaną dokumentację:

ksefka --help                    # lista wszystkich komend
ksefka <komenda> --help          # szczegóły konkretnej komendy

Komendy#

KomendaOpis
Faktury
list-invoicesLista faktur z filtrowaniem
get-invoiceSzczegóły faktury z pozycjami
create-invoiceUtwórz fakturę z pliku JSON lub stdin
finalize-invoicePrzenieś fakturę roboczą do stanu "gotowa do wysłania"
unfinalize-invoiceCofnij finalizację faktury do wersji roboczej
copy-invoiceSkopiuj fakturę jako nowy szkic z dzisiejszą datą
open-invoiceOtwórz fakturę w aplikacji desktopowej
export-invoiceZapisz fakturę jako PDF i/lub XML
mark-invoice-paidOznacz fakturę jako zapłaconą
mark-unpaidCofnij oznaczenie zapłaty
generate-payment-fileWygeneruj plik przelewów (Elixir-0) dla faktur otrzymanych — PRO, 1 darmowy eksport
Pro-formy
list-proformasLista pro-form
get-proformaSzczegóły pro-formy i faktury, która z niej powstała
create-proformaUtwórz pro-formę z pliku JSON lub stdin
convert-proformaPo wpłacie zamień oczekującą pro-formę na fakturę VAT albo zaliczkową
cancel-proformaAnuluj pro-formę
Faktury cykliczne
list-recurringLista harmonogramów
get-recurringSzczegóły harmonogramu
pause-recurringWstrzymaj harmonogram
resume-recurringWznów harmonogram
delete-recurringUsuń harmonogram
generate-recurringWystaw fakturę z harmonogramu teraz
process-recurringWystaw wszystkie zaległe faktury cykliczne
Kontrahenci
list-contractorsLista kontrahentów z wyszukiwaniem
get-contractorSzczegóły kontrahenta
create-contractorDodaj kontrahenta z pliku JSON lub stdin
update-contractorZaktualizuj dane kontrahenta
delete-contractorUsuń (dezaktywuj) kontrahenta
Produkty
list-productsLista produktów/usług z katalogu
get-productSzczegóły produktu
create-productDodaj produkt do katalogu — flagi --vat-exemption-reason-type i --vat-exemption-reason zapisują podstawę zwolnienia przy stawce zw.; dostępne też w update-product
update-productZmień produkt: podane pola zastępują obecne
delete-productUsuń produkt z katalogu (zostaje w historii faktur, znika z list)
Raporty
monthly-summaryPodsumowanie miesięczne (przychody/koszty)
dashboard-statsStatystyki bieżącego miesiąca
list-templatesLista szablonów faktur
Inne
statusAktywne środowisko, firma i liczba faktur
ksef-authorizeZapisz token KSeF firmy
authorizeAktywuj licencję PRO tokenem
mcpUruchom serwer MCP (stdio)
servePraca w tle bez okna aplikacji (PRO), opis niżej
syncSynchronizacja z KSeF teraz, przez demona pracy w tle (PRO)
sendWysyłka do KSeF teraz, przez demona pracy w tle (PRO)
daemon start|stop|status|login-startUruchomienie, zatrzymanie i stan demona pracy w tle, start po zalogowaniu

Większość komend nazywa się tak jak narzędzia serwera MCP, z łącznikiem zamiast podkreślnika (list-invoices to list_invoices). Dawne nazwy nadal działają w tym wydaniu, ale w następnym znikną: zamiast summary użyj monthly-summary, zamiast dashboard — dashboard-stats, zamiast export — export-invoice, zamiast mark-paid — mark-invoice-paid, zamiast payment-file — generate-payment-file, a zamiast proforma list i pozostałych akcji pro-form — list-proformas, get-proforma, create-proforma, convert-proforma i cancel-proforma.

Praca w tle#

Z KSeF rozmawia jeden proces w tle: ksefka serve, dalej nazywany demonem. Otwarta aplikacja uruchamia go sama. Z terminala zlecasz mu pracę komendami sync i send, a uruchamiasz i zatrzymujesz go komendą daemon. Gdy demon nie działa, komendy nie pobierają faktur z KSeF i nic do niego nie wysyłają, chyba że dodasz --local.

Sterowanie z terminala#

  • ksefka sync zleca synchronizację aktywnej firmy (albo firmy z --company-id) i od razu wraca. Z --wait czeka na koniec, najwyżej 15 minut, i wypisuje wynik: nowe i zaktualizowane faktury oraz ostrzeżenia.
  • ksefka send --invoice-id 42 wysyła jedną fakturę (szkic albo zatwierdzoną) i czeka na status z KSeF. Bez --invoice-id zleca wysyłkę wszystkich zatwierdzonych faktur firmy i od razu wraca; wynik zobaczysz na liście faktur.
  • --local przy sync i send wykonuje pracę w procesie komendy, bez demona, i zawsze czeka na wynik. Gdy firmę obsługuje w tej chwili inny proces, sync kończy się komunikatem "Trwa synchronizacja w tle", wysyłka jednej faktury czeka na niego do minuty, a kolejka nie rusza i komenda to zgłasza.
  • ksefka daemon start uruchamia demona w tle dla środowiska z --env (albo ostatnio wybranego w aplikacji) i wraca, gdy demon odpowiada. Gdy demon już działa, komenda zgłasza to i niczego nie zmienia.
  • ksefka daemon stop zatrzymuje demona; ten najpierw kończy bieżący przebieg, najwyżej 30 sekund. Demona uruchomionego przez otwartą aplikację zatrzymasz w aplikacji: Ustawienia → KSeF → Praca w tle.
  • ksefka daemon status wypisuje stan demona: wersję, PID, środowisko, firmy z czasem ostatniej synchronizacji i blokadą po limicie zapytań KSeF.

sync, send, daemon start i daemon login-start on wymagają licencji PRO albo okresu próbnego; daemon status, daemon stop i pozostałe akcje login-start działają bez niej. Gdy demon nie działa, sync, send i daemon status kończą się kodem 4. sync i send dają kod 4 także wtedy, gdy demon działa na innym środowisku niż komenda, bo identyfikatory firm i faktur pochodzą z innej bazy; daemon status pokazuje wtedy demona z jego środowiskiem. Kodem 3 kończą się, po wypisaniu wyniku i krótkiego podsumowania na stderr: sync, gdy części faktur nie pobrał (lista w polu failures), send, gdy KSeF odrzucił fakturę, i send --local, gdy część kolejki się nie wysłała.

$ ksefka sync --wait
{
  "data": {
    "new_invoices": 3,
    "updated_invoices": 1,
    "skipped_duplicates": 0,
    "failed_invoices": 0,
    "warnings": [],
    "failures": [],
    "ksef_floor_reached": false,
    "authenticated": true
  }
}

$ ksefka send --invoice-id 42
{
  "data": {
    "ksef_status": "accepted",
    "ksef_reference_number": "20261101-EE-1A2B3C4D5E-6F",
    "ksef_number": "5260250995-20261101-0100A1B2C3D4-E5",
    "error": null,
    "upo_warning": null
  }
}

$ ksefka sync
{
  "error": "Demon nie działa. Uruchom: ksefka daemon start albo użyj --local"
}
$ echo $?
4

Jak działa demon#

ksefka serve wykonuje bez okna aplikacji tę samą pracę co otwarta KSeFka: synchronizuje faktury z KSeF wszystkich firm z włączoną pracą w tle, wysyła faktury gotowe do wysłania, generuje faktury cykliczne i sprawdza kontrahentów na białej liście VAT. Działa do zamknięcia przez Ctrl+C albo sygnał SIGTERM. Uruchomione z ręki wymaga licencji PRO albo okresu próbnego; otwarta aplikacja uruchamia je sama, bez licencji (niżej).

  • Środowisko KSeF ustala się przy starcie: z opcji --env albo z ostatniego wyboru w aplikacji. Po zmianie środowiska w aplikacji działający serve na poprzednim środowisku (także uruchomiony z ręki) zostaje zatrzymany, a aplikacja uruchamia własny proces na nowym.
  • Na jednym katalogu danych może działać jeden serve. Drugi kończy się od razu kodem 5 i podaje PID działającego.
  • Otwarta aplikacja sama uruchamia serve --follow-parent (swój PID) i w nim wykonuje pracę w tle; taki proces kończy się razem z oknem, a po awarii aplikacja uruchamia go ponownie. Gdy zastanie serve uruchomione z ręki w tej samej wersji i na tym samym środowisku, podłącza się do niego i nie zatrzymuje go przy wyjściu; inną wersję albo inne środowisko zatrzymuje i uruchamia własny proces. Gdy aplikacja jest połączona z serve, "Synchronizuj teraz" i wysyłka z karty faktury też idą przez niego. Zmienna KSEFKA_NO_DAEMON=1 przy starcie aplikacji wyłącza ten mechanizm i przywraca pracę w tle w procesie aplikacji; to samo robi tryb awaryjny w Ustawienia → KSeF → Praca w tle, gdzie też zatrzymasz i uruchomisz proces oraz wybierzesz (PRO), czy ma pracować po zamknięciu okna.
  • Log trafia do pliku daemon.log w katalogu logów (macOS: ~/Library/Logs/pl.nod.ksefka, Windows: %LOCALAPPDATA%\pl.nod.ksefka\logs, Linux: ~/.local/share/pl.nod.ksefka/logs). Po 5 MB plik przechodzi do archiwum; zostają trzy archiwa.

Działającym serve sterujesz przez HTTP na 127.0.0.1. Port i token są w pliku daemon.json w katalogu danych, który może czytać tylko jego właściciel. Każde zapytanie musi mieć nagłówek Authorization: Bearer <token>; bez niego odpowiedź to 401.

  • GET /status: wersja, PID, środowisko, firmy z punktem, do którego doszła synchronizacja, i blokadą po limicie KSeF.
  • POST /sync-now: synchronizacja wszystkich firm albo jednej ({"company_id": 1}) poza harmonogramem. Gdy firmę synchronizuje w tej chwili aplikacja, zlecenie czeka i rusza w jednym z kolejnych przebiegów (co minutę).
  • POST /send-now: wysyłka faktur gotowych do wysłania wszystkich firm, jednej firmy ({"company_id": 1}) albo jednej faktury ({"invoice_id": 42}). Przy jednej fakturze odpowiedź zawiera wynik wysyłki.
  • POST /shutdown: zamknięcie, jak po SIGTERM.
  • GET /events: strumień zdarzeń (Server-Sent Events), np. koniec synchronizacji albo zmiana statusu faktury.

Odpowiedź 409 znaczy, że praca w tle nie obsługuje firmy podanej w zleceniu albo, przy zleceniu bez firmy i bez faktury, żadnej firmy. Praca w tle obsługuje firmę, która ma dane logowania KSeF, włączoną pracę w tle i nie ma zapisanego błędu danych logowania.

Gdy KSeF zablokował NIP firmy po przekroczeniu limitu zapytań, sync-now dla tej firmy i send-now jej faktury odpowiadają 429 z polem retry_after_secs.

# macOS; jq odczytuje port i token z daemon.json
DIR=~/Library/Application\ Support/pl.nod.ksefka
PORT=$(jq -r .port "$DIR/daemon.json")
TOKEN=$(jq -r .token "$DIR/daemon.json")
curl -s -H "Authorization: Bearer $TOKEN" http://127.0.0.1:$PORT/status
curl -s -X POST -H "Authorization: Bearer $TOKEN" http://127.0.0.1:$PORT/sync-now

Start po zalogowaniu#

Żeby demon pracował od zalogowania do systemu, bez otwierania aplikacji, wykonaj ksefka daemon login-start on. Komenda instaluje wpis startowy w menedżerze usług użytkownika (bez uprawnień administratora), przestawia pracę w tle na tryb "zawsze" i wymaga licencji PRO albo okresu próbnego. Na macOS i Linuksie demon rusza od razu (chyba że działa już demon aplikacji), na Windows przy następnym logowaniu. Demon pracuje na środowisku ostatnio wybranym w aplikacji, więc on odmawia, gdy --env wskazuje inne. To samo robi wybór trybu "Zawsze, od zalogowania do systemu" w Ustawienia → KSeF → Praca w tle. W tym trybie aplikacja przy każdym uruchomieniu sprawdza wpis i naprawia go, np. po przeniesieniu aplikacji do innego folderu.

  • ksefka daemon login-start off usuwa wpis i przywraca tryb "tylko gdy aplikacja jest otwarta" w każdym środowisku, które miało tryb "zawsze". Na macOS i Linuksie zatrzymuje też demona uruchomionego ze wpisu. Na Windows taki demon działa do wylogowania; zatrzymasz go komendą ksefka daemon stop.
  • ksefka daemon login-start status wypisuje, czy wpis istnieje, gdzie leży i czy uruchamia zainstalowane CLI.
  • ksefka daemon login-start --print wypisuje treść wpisu dla tego systemu bez instalowania, a z --platform macos|linux|windows dla innego.
  • Wpis uruchamia CLI z "Zainstaluj CLI": ~/.local/bin/ksefka, na Windows ksefka.exe w katalogu aplikacji. Po przeniesieniu aplikacji albo instalacji z obrazu dysku zainstaluj CLI ponownie w Ustawieniach aplikacji, która leży już na swoim miejscu, a potem włącz start po zalogowaniu.
  • Komenda odmawia, gdy KSeFka leży na obrazie dysku albo w tymczasowej kopii (przenieś ją do folderu Programy, otwórz stamtąd i zainstaluj CLI w Ustawieniach), oraz gdy Linux nie ma usług użytkownika systemd, np. w WSL bez systemd=true. Wtedy uruchamiaj demona sam: ksefka daemon start.
  • Bez licencji PRO i okresu próbnego demon ze wpisu kończy się kodem 6 i zapisuje przyczynę w daemon.log. Licencję sprawdza też co 5 minut, więc po końcu okresu próbnego albo unieważnieniu licencji kończy pracę tak samo. Do następnego logowania już nie wraca. Gdy pliku ustawień nie da się odczytać albo token licencji jest nieprawidłowy, demon nie startuje (kod 1), a działający pracuje dalej. Na Linuksie systemd uruchamia go ponownie po każdym wyjściu z kodem innym niż 0, 5 i 6, najwcześniej po minucie. Na macOS launchd robi to tylko po awarii, a Windows wcale: po kodzie 1 demon wraca przy następnym logowaniu.
  • Otwarta aplikacja w tej samej wersji i na tym samym środowisku podłącza się do demona i nie zatrzymuje go przy wyjściu. Aplikacja w innej wersji albo na innym środowisku zatrzymuje go i uruchamia własny proces. Demon ze wpisu wraca wtedy przy następnym logowaniu, a do tego czasu pracę po zamknięciu okna wyznacza tryb wybrany w aplikacji.

macOS: plik ~/Library/LaunchAgents/pl.nod.ksefka.daemon.plist, który włącza launchctl bootstrap gui/$(id -u) <plik>. launchd nie rozwija ~, więc ścieżka do CLI jest pełna. W szablonach wpisz swoją nazwę użytkownika zamiast NAZWA_UZYTKOWNIKA albo wygeneruj wpis dla siebie komendą ksefka daemon login-start --print.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key>
  <string>pl.nod.ksefka.daemon</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Users/NAZWA_UZYTKOWNIKA/.local/bin/ksefka</string>
    <string>serve</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
  <key>KeepAlive</key>
  <dict>
    <key>Crashed</key>
    <true/>
  </dict>
  <key>ThrottleInterval</key>
  <integer>60</integer>
  <key>ProcessType</key>
  <string>Background</string>
</dict>
</plist>

Linux: plik ~/.config/systemd/user/ksefka-daemon.service, który włącza systemctl --user enable --now ksefka-daemon.service. Usługa użytkownika kończy się przy wylogowaniu; żeby działała dalej, wykonaj loginctl enable-linger $USER.

[Unit]
Description=KSeFka - praca w tle (synchronizacja z KSeF)
After=network-online.target

[Service]
ExecStart="/home/NAZWA_UZYTKOWNIKA/.local/bin/ksefka" serve
Restart=on-failure
RestartSec=60
# 5: demon już działa (np. pod aplikacją), 6: licencja nie pozwala na pracę w tle
RestartPreventExitStatus=5 6

[Install]
WantedBy=default.target

Windows: wartość KSeFkaDaemon w kluczu HKCU\Software\Microsoft\Windows\CurrentVersion\Run. conhost --headless uruchamia demona bez okna konsoli.

conhost.exe --headless "C:\Users\NAZWA_UZYTKOWNIKA\AppData\Local\KSeFka\ksefka.exe" serve
  • Token KSeF zapisany w KSeFce jest zaszyfrowany kluczem związanym z komputerem. Demon na innej maszynie (serwer, NAS) z kopią bazy nie odczyta go; wykonaj tam ksefka ksef-authorize <token>. Uruchamianie demona na innej maszynie niż aplikacja opisujemy tylko tutaj i nie obejmuje go pomoc techniczna.
  • Baza działa w trybie WAL: kopia samych plików .db przy działającej aplikacji albo demonie może być niepełna. Kopiuj razem z plikami -wal i -shm albo przy zamkniętej aplikacji i zatrzymanym demonie (ksefka daemon stop). Kopię bez tych zastrzeżeń zrobisz w aplikacji: Ustawienia → Import / Eksport → Pełny backup danych.

Wejście JSON#

Komendy tworzące obiekty (np. create-invoice, create-contractor) przyjmują dane jako:

# z pliku
ksefka create-invoice --from-json faktura.json

# ze stdin (pipe)
cat faktura.json | ksefka create-invoice --from-json -

# lub przekierowanie
ksefka create-invoice --from-json - < faktura.json

Strukturę JSON znajdziesz w pomocy komendy: ksefka create-invoice --help.

Kody wyjścia#

Komendy zwracają wynik jako JSON na stdout, w polu data. Skrypt rozpoznaje, co się stało, po kodzie wyjścia:

  • 0 — komenda wykonała pracę w całości
  • 1 — komenda nie wykonała pracy; na stdout zamiast data jest { "error": "..." }
  • 2 — błędne wywołanie (nieznana flaga, brak argumentu); opis na stderr, nic na stdout
  • 3 — komenda wykonała część pracy. Wynik jest na stdout jak przy kodzie 0. Tak kończą się sync i send opisane w sekcji "Praca w tle" oraz process-recurring, gdy choć jeden harmonogram został bez faktury: data zawiera wynik każdego harmonogramu, obok są liczniki generated_count i failed_count, a stderr wymienia nieudane harmonogramy z powodem.
  • 4 — demon nie działa (sync, send, daemon status) albo działa na innym środowisku (sync, send)
  • 5 — serve już działa na tym katalogu danych
  • 6 — brak licencji PRO i okresu próbnego przy pracy w tle bez okna: serve bez --follow-parent przy starcie albo gdy licencja przestanie pozwalać (koniec okresu próbnego, unieważnienie), serve --follow-parent po zamknięciu aplikacji w trybie pracy po zamknięciu okna
# cron: alarm, gdy process-recurring nie wykonał pracy albo któryś harmonogram został bez faktury
ksefka process-recurring > /tmp/cykliczne.json || echo "process-recurring: kod $?" | mail -s "KSeFka" ja@firma.pl