Skip to content

Latest commit

 

History

History
857 lines (673 loc) · 21.9 KB

File metadata and controls

857 lines (673 loc) · 21.9 KB

KSeF Python CLI (ksef)

Ten dokument opisuje aktualne CLI 1:1 wobec implementacji w src/ksef_client/cli.

Cel

CLI ma skracac droge od instalacji do pierwszej realnej operacji KSeF: init -> auth -> invoice/send/upo.

CLI wysyla domyslnie naglowek X-Error-Format: problem-details, dzieki czemu bledy 400 i 429 sa renderowane z bogatszymi hintami, jesli KSeF zwroci application/problem+json.

Co jest zaimplementowane

  • onboarding i profile:
    • init
    • profile list/show/use/create/set/delete
  • auth:
    • auth login-token
    • auth login-xades
    • auth status
    • auth refresh
    • auth revoke-self-token
    • auth logout
  • diagnostyka:
    • health check
  • latarnia:
    • lighthouse status
    • lighthouse messages
  • faktury i UPO:
    • invoice list, invoice download
    • send online, send batch, send status
    • session list/show/status/export/import/drop
    • session online open/send/close
    • session batch open/upload/close
    • upo get, upo wait
  • eksport:
    • export run, export status
  • output:
    • human
    • --json (stabilny envelope)

Szybki start (2-3 minuty)

  1. Instalacja:
pip install -e .[cli]
  1. Inicjalizacja profilu:
ksef init --non-interactive --name demo --env DEMO --context-type nip --context-value <NIP> --set-active
  1. Logowanie tokenem + szybka weryfikacja sesji:
ksef auth login-token
ksef auth status
ksef profile show
  1. Pierwsze operacje:
ksef invoice list --from 2026-01-01 --to 2026-01-31
ksef send online --invoice ./fa.xml --wait-upo --save-upo ./out/upo-online.xml
ksef send online --invoice ./fa.xml --save-session online-demo
ksef session show --id online-demo
ksef invoice download --ksef-number <KSEF_NUMBER> --out ./out/
  1. Manualny flow resumable:
ksef session online open --id online-demo
ksef session online send --id online-demo --invoice ./fa.xml --wait-status
ksef session online close --id online-demo

Troubleshooting

Bazowa instalacja pip install -e . albo pip install ksef-client nie instaluje zależności CLI. W takim przypadku uruchomienie ksef kończy się kontrolowanym komunikatem:

Install CLI dependencies with: pip install "ksef-client[cli]"

To zachowanie jest poprawne. Aby korzystać z CLI, doinstaluj extra cli.

Drzewo komend

ksef
  init
  profile
    list
    show
    use
    create
    set
    delete
  auth
    login-token
    login-xades
    status
    refresh
    logout
  health
    check
  lighthouse
    status
    messages
  invoice
    list
    download
  send
    online
    batch
    status
  session
    list
    show
    status
    export
    import
    drop
    online
      open
      send
      close
    batch
      open
      upload
      close
  upo
    get
    wait
  export
    run
    status

Opcje globalne

Usage: ksef [OPTIONS] COMMAND [ARGS]...

Options:
  --profile TEXT
  --json
  -v, --verbose
  --no-color
  --version
  --help

Zachowanie profilu:

  • gdy podasz --profile, CLI uzywa tej nazwy,
  • gdy podasz nieistniejacy --profile, CLI zwraca blad walidacji (exit code 2),
  • gdy nie podasz, CLI bierze active_profile z configu,
  • gdy brak active_profile, komendy biznesowe zwracaja blad konfiguracji (exit code 6).
  • gdy nie podasz --base-url, CLI bierze kolejno: CLI option -> KSEF_BASE_URL -> profile.base_url -> DEMO.

Brak aktywnego profilu:

  • komendy auth, health, invoice, send, upo, export wymagaja aktywnego profilu,
  • komendy session ... rowniez wymagaja aktywnego profilu,
  • komendy lighthouse ... dzialaja bez profilu (publiczne API Latarni),
  • jesli profil nie jest ustawiony, CLI zwraca czytelny blad z podpowiedzia:
    • ksef init --set-active
    • ksef profile use --name <name>
    • albo uruchomienie komendy z --profile <name>.
  • komendy onboardingu (init, profile ...) dzialaja bez aktywnego profilu.

Srodowiska i base_url (aby uniknac przypadkowego DEMO):

  • ksef init --env DEMO ustawia https://api-demo.ksef.mf.gov.pl,
  • ksef init --env TEST ustawia https://api-test.ksef.mf.gov.pl,
  • ksef init --env PROD ustawia https://api.ksef.mf.gov.pl.
  • --base-url ma najwyzszy priorytet i nadpisuje --env.
  • po zmianie profilu/srodowiska uruchom:
    • ksef profile show
    • ksef auth status

Komendy onboarding/profile

ksef init

  • tryb interaktywny (domyslnie): CLI pyta o brakujace dane,
  • tryb nieinteraktywny: --non-interactive + komplet danych,
  • --set-active ustawia profil jako aktywny.
Usage: ksef init [OPTIONS]

Options:
  --name TEXT
  --env TEXT
  --base-url TEXT
  --context-type TEXT
  --context-value TEXT
  --non-interactive
  --set-active

ksef profile create

Usage: ksef profile create [OPTIONS]

Options:
  --name TEXT                 [required]
  --env TEXT
  --base-url TEXT
  --context-type TEXT         [default: nip]
  --context-value TEXT        [required]
  --set-active

Uwagi:

  • podaj --env albo --base-url (gdy oba puste, fallback to DEMO),
  • profile set --key env --value TEST automatycznie przestawia tez base_url.

ksef profile show

Usage: ksef profile show [OPTIONS]

Options:
  --name TEXT

Uwagi:

  • bez --name komenda bierze aktywny profil,
  • gdy brak aktywnego profilu i brak --name, CLI zwraca blad konfiguracji (exit code 6).

ksef profile set

Usage: ksef profile set [OPTIONS]

Options:
  --name TEXT                                 [required]
  --key [env|base_url|context_type|context_value] [required]
  --value TEXT                                [required]

Komendy auth

ksef auth login-token

Usage: ksef auth login-token [OPTIONS]

Options:
  --ksef-token TEXT
  --context-type TEXT
  --context-value TEXT
  --base-url TEXT
  --poll-interval FLOAT     [default: 2.0]
  --max-attempts INTEGER    [default: 90]
  --save/--no-save          [default: save]

Zrodlo tokenu:

  • --ksef-token ma najwyzszy priorytet,
  • gdy --ksef-token nie jest podany, CLI czyta KSEF_TOKEN.
  • gdy --ksef-token nie jest podany i brak KSEF_TOKEN, CLI pyta o token ukrytym promptem (tryb interaktywny).
  • podanie sekretu bezposrednio w --ksef-token <wartosc> powoduje ostrzezenie runtime (bez ujawniania sekretu).

Fallback kontekstu:

  • context_type i context_value sa brane kolejno z: CLI option -> env (KSEF_CONTEXT_*) -> aktywny profil.

ksef auth login-xades

Usage: ksef auth login-xades [OPTIONS]

Options:
  --pkcs12-path TEXT
  --pkcs12-password TEXT
  --cert-pem TEXT
  --key-pem TEXT
  --key-password TEXT
  --context-type TEXT
  --context-value TEXT
  --base-url TEXT
  --subject-identifier-type TEXT [default: certificateSubject]
  --poll-interval FLOAT          [default: 2.0]
  --max-attempts INTEGER         [default: 90]
  --save/--no-save               [default: save]

Walidacja:

  • uzyj dokladnie jednego zrodla certyfikatu:
    • --pkcs12-path, albo
    • para --cert-pem + --key-pem.
  • gdy hasla (--pkcs12-password, --key-password) nie sa podane, CLI moze zapytac o nie ukrytym promptem (tryb interaktywny; puste wejscie = brak hasla).
  • podanie hasla bezposrednio w opcji (--pkcs12-password <wartosc>, --key-password <wartosc>) powoduje ostrzezenie runtime (bez ujawniania sekretu).

Fallback kontekstu:

  • context_type i context_value sa brane kolejno z: CLI option -> env (KSEF_CONTEXT_*) -> aktywny profil.

ksef auth refresh

Usage: ksef auth refresh [OPTIONS]

Options:
  --base-url TEXT
  --save/--no-save          [default: save]

Kiedy uzywac:

  • gdy access token wygasl, a refresh token jest nadal wazny,
  • gdy chcesz odswiezyc token bez ponownego pelnego logowania.

Uwagi:

  • komenda wymaga zapisanych tokenow dla wybranego profilu,
  • --save aktualizuje zapisany access token.

ksef auth logout

Usage: ksef auth logout [OPTIONS]

Kiedy uzywac:

  • gdy chcesz usunac lokalnie zapisane tokeny dla biezacego profilu,
  • przed przelaczeniem konta lub kontekstu autoryzacji.

ksef auth revoke-self-token

Usage: ksef auth revoke-self-token [OPTIONS]

Kiedy uzywac:

  • gdy chcesz uniewaznic token KSeF, ktorym wykonano auth login-token,
  • gdy po uniewaznieniu chcesz od razu wyczyscic lokalnie zapisane accessToken i refreshToken.

Uwagi:

  • komenda wymaga sesji zalogowanej przez auth login-token,
  • numer referencyjny tokenu jest pobierany z cache zapisanego podczas logowania.

ksef health check

Usage: ksef health check [OPTIONS]

Options:
  --dry-run
  --check-auth
  --check-certs
  --base-url TEXT

ksef lighthouse status

Usage: ksef lighthouse status [OPTIONS]

Options:
  --base-url TEXT

Uwagi:

  • komenda korzysta z publicznego API Latarni (bez tokenu dostepowego),
  • domyslnie base URL Latarni mapowany jest z profilu KSeF (TEST/DEMO -> latarnia TEST, PROD -> latarnia PROD),
  • gdy brak profilu i brak override (--base-url/KSEF_LIGHTHOUSE_BASE_URL), uzywana jest domyslnie latarnia test: https://api-latarnia-test.ksef.mf.gov.pl,
  • --base-url lub KSEF_LIGHTHOUSE_BASE_URL pozwala nadpisac endpoint Latarni.

ksef lighthouse messages

Usage: ksef lighthouse messages [OPTIONS]

Options:
  --base-url TEXT

invoice / send / upo / export

ksef invoice list

Usage: ksef invoice list [OPTIONS]

Options:
  --from TEXT
  --to TEXT
  --subject-type TEXT
  --date-type TEXT          [default: Issue]
  --page-size INTEGER       [default: 10, min: 10, max: 250]
  --page-offset INTEGER     [default: 0]
  --sort-order [Asc|Desc]   [default: Desc]
  --base-url TEXT

Uwagi:

  • bez --subject-type CLI agreguje wyniki dla wszystkich typów (Subject1, Subject2, Subject3, SubjectAuthorized),
  • podanie --subject-type zachowuje poprzednie, jawne filtrowanie do jednego kontekstu podmiotu.
  • zakres --from/--to nie moze przekraczac 3 miesiecy.

Kontrakt data dla ksef invoice list --json:

  • count: liczba rekordow w biezacej stronie po filtracji,
  • from, to: efektywny zakres dat wykorzystany w zapytaniu,
  • items: lista rekordow faktur,
  • has_more: czy API sygnalizuje kolejne dane do pobrania,
  • is_truncated: czy API zwrocilo odpowiedz obcieta po stronie serwera,
  • permanent_storage_hwm_date: znacznik HWM z API (dla synchronizacji przyrostowej),
  • continuation_token: pole kompatybilnosciowe; CLI nie generuje sztucznej wartosci i moze byc null.

ksef invoice download

Usage: ksef invoice download [OPTIONS]

Options:
  --ksef-number TEXT   [required]
  --out TEXT           [required]
  --as TEXT            [default: xml]
  --overwrite
  --base-url TEXT

Uwagi:

  • --out moze wskazywac plik albo katalog,
  • sciezka bez rozszerzenia jest traktowana jako plik (np. ./out/invoice).

ksef send online

Usage: ksef send online [OPTIONS]

Options:
  --invoice TEXT            [required]
  --system-code TEXT        [default: FA (3)]
  --schema-version TEXT     [default: 1-0E]
  --form-value TEXT         [default: FA]
  --upo-v43
  --wait-status
  --wait-upo
  --poll-interval FLOAT     [default: 2.0]
  --max-attempts INTEGER    [default: 60]
  --save-upo TEXT
  --save-session TEXT
  --save-upo-overwrite
  --base-url TEXT

Uwagi:

  • --save-upo wymaga --wait-upo.
  • --save-upo bez rozszerzenia jest traktowane jako sciezka pliku.
  • --save-session <id> zapisuje lokalny checkpoint resumable sesji pod wskazanym identyfikatorem.
  • Przy udanym zakonczeniu komenda nadal zamyka sesje; checkpoint sluzy glownie do inspekcji oraz odzyskania flow po przerwaniu lub bledzie po zapisaniu checkpointu.
  • --save-upo-overwrite pozwala nadpisac istniejacy plik UPO wskazany przez --save-upo.
  • Dla FA_RR (1) z --schema-version 1-1E uzyj --form-value FA_RR; CLI normalizuje historyczne RR do FA_RR.

ksef send batch

Usage: ksef send batch [OPTIONS]

Options:
  --zip TEXT
  --dir TEXT
  --system-code TEXT        [default: FA (3)]
  --schema-version TEXT     [default: 1-0E]
  --form-value TEXT         [default: FA]
  --parallelism INTEGER     [default: 4]
  --upo-v43
  --wait-status
  --wait-upo
  --poll-interval FLOAT     [default: 2.0]
  --max-attempts INTEGER    [default: 120]
  --save-upo TEXT
  --save-session TEXT
  --save-upo-overwrite
  --base-url TEXT

Walidacja:

  • dokladnie jedno z --zip albo --dir.
  • --save-session <id> zapisuje lokalny checkpoint resumable sesji pod wskazanym identyfikatorem.
  • Przy udanym zakonczeniu komenda nadal zamyka sesje; checkpoint sluzy glownie do inspekcji oraz odzyskania flow po przerwaniu lub bledzie po zapisaniu checkpointu.
  • --save-upo-overwrite pozwala nadpisac istniejacy plik UPO wskazany przez --save-upo.
  • Dla FA_RR (1) z --schema-version 1-1E uzyj --form-value FA_RR; CLI normalizuje historyczne RR do FA_RR.

Resumable sessions

CLI utrzymuje osobny checkpoint workflow dla wznowien po restarcie procesu. To cos wiecej niz lekki OnlineSessionState / BatchSessionState z SDK:

  • checkpoint online przechowuje id, profile, base_url, stage, session_state, last_invoice_ref, sent_invoice_refs,
  • checkpoint batch przechowuje id, profile, base_url, stage, session_state, payload_source, uploaded_ordinals, last_upo_ref.

Wazne granice odpowiedzialnosci:

  • checkpoint nie przechowuje tokenow,
  • checkpoint batch nie embeduje ZIP-a ani XML-i,
  • resume batch wymaga zachowania tego samego ZIP-a albo tego samego katalogu zrodlowego.

Przy wygaslym tokenie najpierw odswiez sesje:

ksef auth refresh

albo zaloguj sie ponownie, a dopiero potem wykonaj ksef session ....

ksef session list

Usage: ksef session list

Zwraca checkpointy zapisane dla aktywnego profilu.

ksef session show

Usage: ksef session show --id TEXT

Pokazuje skrot i pelny JSON checkpointu.

ksef session status

Usage: ksef session status [OPTIONS]

Options:
  --id TEXT                 [required]
  --invoice-ref TEXT

Uwagi:

  • bez --invoice-ref CLI pobiera status sesji,
  • z --invoice-ref CLI pobiera status konkretnej faktury w sesji online.

ksef session export

Usage: ksef session export [OPTIONS]

Options:
  --id TEXT                 [required]
  --out TEXT                [required]

Eksportuje checkpoint do wskazanego pliku JSON albo katalogu.

ksef session import

Usage: ksef session import [OPTIONS]

Options:
  --in TEXT                 [required]
  --id TEXT

Uwagi:

  • importowany checkpoint musi nalezec do wybranego profilu,
  • --id pozwala nadpisac identyfikator podczas importu.

ksef session drop

Usage: ksef session drop --id TEXT

Usuwa lokalny checkpoint. Nie wykonuje zadnych operacji na sesji po stronie KSeF.

ksef session online open

Usage: ksef session online open [OPTIONS]

Options:
  --id TEXT                 [required]
  --system-code TEXT        [default: FA (3)]
  --schema-version TEXT     [default: 1-0E]
  --form-value TEXT         [default: FA]
  --upo-v43
  --base-url TEXT

Otwiera sesje online i zapisuje checkpoint w stanie opened.

ksef session online send

Usage: ksef session online send [OPTIONS]

Options:
  --id TEXT                 [required]
  --invoice TEXT            [required]
  --wait-status
  --wait-upo
  --poll-interval FLOAT     [default: 2.0]
  --max-attempts INTEGER    [default: 60]
  --save-upo TEXT
  --save-upo-overwrite

Uwagi:

  • komenda wznawia sesje z checkpointu i wysyla kolejna fakture,
  • po sukcesie aktualizuje last_invoice_ref i sent_invoice_refs,
  • --save-upo wymaga --wait-upo.

ksef session online close

Usage: ksef session online close --id TEXT

Zamyka sesje online i aktualizuje checkpoint do stanu closed.

ksef session batch open

Usage: ksef session batch open [OPTIONS]

Options:
  --id TEXT                 [required]
  --zip TEXT
  --dir TEXT
  --system-code TEXT        [default: FA (3)]
  --schema-version TEXT     [default: 1-0E]
  --form-value TEXT         [default: FA]
  --upo-v43
  --base-url TEXT

Walidacja:

  • dokladnie jedno z --zip albo --dir.

Komenda otwiera sesje batch i zapisuje checkpoint z deskryptorem payload_source.

ksef session batch upload

Usage: ksef session batch upload [OPTIONS]

Options:
  --id TEXT                 [required]
  --parallelism INTEGER     [default: 4]

Uwagi:

  • CLI odtwarza ZIP z payload_source,
  • weryfikuje, czy hash i rozmiar zrodla nie zmienily sie od czasu utworzenia checkpointu,
  • wznawia upload tylko brakujacych partow, pomijajac uploaded_ordinals.

ksef session batch close

Usage: ksef session batch close [OPTIONS]

Options:
  --id TEXT                 [required]
  --wait-status
  --wait-upo
  --poll-interval FLOAT     [default: 2.0]
  --max-attempts INTEGER    [default: 120]
  --save-upo TEXT
  --save-upo-overwrite

Uwagi:

  • komenda zamyka sesje batch bez potrzeby ponownego ladowania ZIP-a,
  • --wait-status i --wait-upo dzialaja analogicznie do send batch,
  • po odczycie statusu CLI zapisuje last_upo_ref w checkpointcie.

Przyklady resume flow

Manualny online:

ksef session online open --id online-demo
ksef session online send --id online-demo --invoice ./fa.xml --wait-status
ksef session online close --id online-demo

Manualny batch:

ksef session batch open --id batch-demo --zip ./batch.zip
ksef session batch upload --id batch-demo --parallelism 4
ksef session batch close --id batch-demo --wait-status --wait-upo

One-shot z checkpointem i recovery po przerwaniu:

ksef send batch --zip ./batch.zip --save-session batch-demo
# jesli proces zostal przerwany po zapisaniu checkpointu:
ksef session show --id batch-demo
ksef session batch upload --id batch-demo --parallelism 4
ksef session batch close --id batch-demo --wait-status --wait-upo

ksef upo get

Usage: ksef upo get [OPTIONS]

Options:
  --session-ref TEXT    [required]
  --invoice-ref TEXT
  --ksef-number TEXT
  --upo-ref TEXT
  --out TEXT            [required]
  --overwrite
  --base-url TEXT

Walidacja:

  • dokladnie jedno z: --invoice-ref, --ksef-number, --upo-ref.

ksef upo wait

Usage: ksef upo wait [OPTIONS]

Options:
  --session-ref TEXT         [required]
  --invoice-ref TEXT
  --upo-ref TEXT
  --batch-auto
  --poll-interval FLOAT      [default: 2.0]
  --max-attempts INTEGER     [default: 60]
  --out TEXT
  --overwrite
  --base-url TEXT

Walidacja:

  • dokladnie jeden tryb: --invoice-ref albo --upo-ref albo --batch-auto.

ksef export run

Usage: ksef export run [OPTIONS]

Options:
  --from TEXT
  --to TEXT
  --date-type TEXT          [default: Issue]
  --subject-type TEXT        [default: Subject1]
  --restrict-to-permanent-storage-hwm-date / --no-restrict-to-permanent-storage-hwm-date
  --only-metadata
  --poll-interval FLOAT      [default: 2.0]
  --max-attempts INTEGER     [default: 120]
  --out TEXT                 [required]
  --base-url TEXT

Uwagi:

  • --only-metadata pobiera tylko _metadata.json bez XML faktur.
  • dla eksportu przyrostowego uzyj --date-type PermanentStorage razem z --restrict-to-permanent-storage-hwm-date.

Exit codes

  • 0 sukces
  • 2 blad walidacji
  • 3 blad auth/token
  • 4 retry exhausted / rate-limit
  • 5 blad API KSeF
  • 6 blad konfiguracji/srodowiska
  • 7 circuit breaker open
  • 8 blad I/O

Bezpieczenstwo tokenow

  • Rekomendacja dla sekretow auth: nie podawaj ich bezposrednio w argumentach CLI.

    • interaktywnie: pomin opcje sekretu i wpisz wartosc w ukrytym prompcie,
    • automatyzacja: uzyj zmiennych srodowiskowych (np. KSEF_TOKEN) albo managera sekretow.
  • Domyslnie CLI wymaga systemowego keyringu do zapisu tokenow.

  • Gdy keyring jest niedostepny, mozliwy jest fallback szyfrowany przez klucz z env:

KSEF_CLI_TOKEN_STORE_KEY=<TWOJ_KLUCZ>
  • Plaintext fallback do tokens.json pozostaje domyslnie zablokowany i jest tylko trybem awaryjnym.
  • Mozesz go jawnie wlaczyc (niezalecane) tylko gdy to konieczne:
KSEF_CLI_ALLOW_INSECURE_TOKEN_STORE=1
  • Gdy CLI faktycznie uzyje plaintext fallback, wypisuje jawne ostrzezenie o niezabezpieczonym zapisie tokenow.
  • Na Windows plaintext fallback jest zablokowany nawet po ustawieniu tej zmiennej; uzyj keyringa albo fallbacku szyfrowanego.
  • Gdy keyring jest obecny, ale backend zwraca blad, CLI automatycznie przechodzi na dostepny fallback (KSEF_CLI_TOKEN_STORE_KEY lub awaryjny plaintext poza Windows).
  • ksef health check oraz diagnostyka preflight pokazuja aktualny tryb polityki token-store jako jedno z:
    • keyring
    • encrypted-fallback
    • plaintext-fallback
    • unavailable

Lokalizacja token fallback:

  • Windows: %LOCALAPPDATA%/ksef-cli/tokens.json
  • Linux/macOS: ~/.cache/ksef-cli/tokens.json

Odporność configu

  • Zapis config.json jest atomowy (tmp + rename), aby ograniczyc ryzyko uszkodzenia pliku.
  • Gdy config.json jest uszkodzony (np. niepoprawny JSON), CLI przenosi go do pliku config.corrupt-<timestamp>.json i startuje z pustym configiem.

Lokalizacje plikow CLI

  • Konfiguracja:
    • Windows: %APPDATA%/ksef-cli/config.json
    • Linux/macOS: ~/.config/ksef-cli/config.json
  • Cache metadanych:
    • Windows: %LOCALAPPDATA%/ksef-cli/cache.json
    • Linux/macOS: ~/.cache/ksef-cli/cache.json
  • Checkpointy resumable sesji:
    • Windows: %LOCALAPPDATA%/ksef-cli/sessions/<profile>/<id>.json
    • Linux/macOS: ~/.cache/ksef-cli/sessions/<profile>/<id>.json
  • Fallback token store:
    • Windows: %LOCALAPPDATA%/ksef-cli/tokens.json
    • Linux/macOS: ~/.cache/ksef-cli/tokens.json
  • Kopia uszkodzonego configu:
    • config.corrupt-<timestamp>.json w tym samym katalogu co config.json.

Uwagi:

  • checkpointy sesji sa zapisywane atomowo,
  • poza Windows CLI probuje wymusic uprawnienia 0600,
  • checkpointy nie zawieraja tokenow ani tresci faktur.

JSON contract (--json)

{
  "ok": true,
  "command": "invoice.list",
  "profile": "demo",
  "data": {},
  "errors": [],
  "meta": {
    "duration_ms": 120
  }
}

Uwagi:

  • w zdarzeniach informacyjnych (command=info) pole profile moze byc null,
  • w bledzie: ok=false, a errors zawiera code, message, opcjonalnie hint.