Skip to content

Developer notes

Builder::invoice() turns fn_get_order_info() into a neutral invoice model; Ksef\Fa3::write() writes the FA(3) XML (schema FA (3) version 1-0E, namespace http://crd.gov.pl/wzor/2025/06/25/13775/) from that model. The model is stored with the document, so the invoice never changes when the order changes later.

Order data FA(3)
Seller connection (NIP, name, address, contact) Podmiot1
Buyer tax ID: Polish NIP / EU VAT ID / other / none Podmiot2: NIP / KodUE+NrVatUE / KodKraju+NrID / BrakID; JST and GV = 2
Issue date (Europe/Warsaw), number, place P_1, P_2, P_1M
Products, shipping, payment surcharge FaWiersz lines; discounts spread over the product lines as P_10
Taxes included in prices gross method: P_9B, P_11A, VAT per rate = gross x rate / (100 + rate)
Taxes added to prices net method: P_9A, P_11, VAT per rate = net x rate
Rate codes P_12: 23, 22, 8, 7, 5, 4, 3, 0 KR, 0 WDT, 0 EX, zw, oo, np I, np II; OSS: P_12_XII + Procedura WSTO_EE
Totals P_13_x / P_14_x per rate group, P_14_xW (VAT in PLN) for other currencies, P_15
Reverse charge, split payment, exemption Adnotacje: P_18, P_18A, Zwolnienie (P_19 + basis)
Paid or due date, payment form, bank account Platnosc
Order number and date WarunkiTransakcji/Zamowienia
KRS, REGON, BDO, footer Stopka
Corrections RodzajFaktury KOR, PrzyczynaKorekty, TypKorekty, DaneFaKorygowanej (NrKSeFFaKorygowanej), lines before (StanPrzed) and after

The official XSD files are in app/addons/kv_ksef/resources/xsd/; Validator::xsd() validates every document offline before it is sent.

Ksef\Api implements the calls the add-on needs from the official OpenAPI description:

  1. GET /security/public-key-certificates (cached 12 h per seller).
  2. Token login: POST /auth/challenge, POST /auth/ksef-token with token|timestampMs encrypted by RSA-OAEP (SHA-256, MGF1-SHA-256), GET /auth/{ref}, POST /auth/token/redeem. Certificate login: POST /auth/xades-signature with the AuthTokenRequest signed as XAdES-BES (enveloped, exclusive c14n, RSA-SHA256 or ECDSA-SHA256).
  3. Access tokens are cached encrypted and refreshed with POST /auth/token/refresh.
  4. POST /sessions/online with a fresh AES-256 key per run (encrypted with RSA-OAEP), POST /sessions/online/{ref}/invoices (AES-256-CBC, SHA-256 hashes, offlineMode), GET /sessions/{ref}/invoices/{invoiceRef} until status 200, GET .../upo, POST /sessions/online/{ref}/close.
  5. GET /invoices/ksef/{ksefNumber} and POST /invoices/query/metadata for downloads and incoming invoices.

KSeF numbers are checked with their CRC-8. Status 440 (duplicate) after a lost answer adopts the original KSeF number; 405/500/550 are retried; other 4xx codes reject the document with KSeF’s reason.

Base URLs: https://api-test.ksef.mf.gov.pl/v2, https://api-demo.ksef.mf.gov.pl/v2, https://api.ksef.mf.gov.pl/v2; verification links on qr-test., qr-demo. and qr.ksef.mf.gov.pl.

Constants for config.local.php:

  • KV_KSEF_CA_FILE: path to a CA bundle when the server’s PHP has none configured (cURL error 60).
  • KV_KSEF_BASE_URL: a local mock server (only honoured on development hosts, for tests).
Table Contents
?:kv_ksef_documents Invoices and corrections: number, status, KSeF number, references, XML, UPO, model (JSON), checks
?:kv_ksef_sellers Connection and seller data per seller (0 = store / marketplace, storefront or vendor id); secrets encrypted with AES-256-GCM using a key derived from the store’s crypt key
?:kv_ksef_counters Gapless number series per seller and period
?:kv_ksef_maps Tax and payment mapping
?:kv_ksef_products GTU code, Annex 15 flag and unit per product
?:kv_ksef_log Document and connection history (no secrets, no invoice content), kept one year

change_order_status (create invoice / full correction), delete_order (documents are kept and marked), update_product_post, delete_product_post. Template hooks: orders:tabs_extra and products:update_product_amount in the admin, orders:info on the storefront order page. Identical in 4.17.2 and 4.21.2.

use Tygh\Addons\KvKsef\Issuer;
use Tygh\Addons\KvKsef\Sender;
$res = Issuer::issueForOrder($order_id, 'manual'); // ['doc' => ..., 'error' => '', 'created' => bool]
$cor = Issuer::correct($invoice_doc_id, null, 'Cancelled'); // null = full correction, or [line index => new qty]
$stats = Sender::run(); // sends everything due

Nothing is printed on full-page-cached storefront pages; the customer card is on the order page (a session page) and the downloads are private, no-store responses.

  • Invoices & Credit Notes: with numbering set to Automatic, KSeF invoices use its invoice numbers.
  • EU VAT Number Validation and EU e-Invoicing: their VAT ID field is used for the buyer tax ID; the checked number of EU VAT Number Validation wins.
  • Sell by Weight & Length: measured quantities and units are used on the invoice lines.
app/addons/kv_ksef/
addon.xml init.php func.php
controllers/backend/kv_ksef.php documents, document page, connection, mapping, incoming, corrections, queue, cron
controllers/backend/orders.post.php KSeF tab of the order page
controllers/backend/products.post.php KSeF product fields
controllers/frontend/kv_ksef.php customer download / printable view, cron URL
controllers/frontend/orders.post.php KSeF card on the customer order page
resources/xsd/ official FA(3) schema files
schemas/ menu, permissions, context menu, settings variants
Tygh/Addons/KvKsef/Ksef/ Api, Crypto, Xades, Fa3, Xml, Qr (no CS-Cart dependency)
Tygh/Addons/KvKsef/ Builder, Issuer, Sender, Documents, Sellers, Client, Validator, ...
Tygh/Addons/KvKsef/License/ license client
Tygh/Addons/KvKsef/Upgrade/Synchronizer.php
design/backend/templates/addons/kv_ksef/ admin pages, hooks, settings info, license card
design/backend/css/addons/kv_ksef/ admin styles
var/themes_repository/responsive/templates/addons/kv_ksef/ customer card, printable view
var/themes_repository/responsive/css/addons/kv_ksef/ storefront styles
var/langs/en/addons/kv_ksef.po

The license client (License\Client) reads only its stored state on each request; checks run in the admin panel. See License.